From 967ca09a2cf09f4e76b07cff409835dcc1cec9da Mon Sep 17 00:00:00 2001 From: kudzu_cp <6d05c8c8ef5431987001abfdb2eadc9593ac9498> Date: Wed, 13 Jul 2011 05:05:35 +0000 Subject: [PATCH] GDT work --- .../Cosmos.IL2CPU.X86/CosmosAssembler.cs | 17 ++- .../Cosmos.Core.Plugs/Assemblers/CreateGDT.cs | 119 ++++++++++++++---- 2 files changed, 102 insertions(+), 34 deletions(-) diff --git a/source2/IL2CPU/Cosmos.IL2CPU.X86/CosmosAssembler.cs b/source2/IL2CPU/Cosmos.IL2CPU.X86/CosmosAssembler.cs index 294c41a5e..ac783e6f9 100644 --- a/source2/IL2CPU/Cosmos.IL2CPU.X86/CosmosAssembler.cs +++ b/source2/IL2CPU/Cosmos.IL2CPU.X86/CosmosAssembler.cs @@ -48,6 +48,7 @@ namespace Cosmos.IL2CPU.X86 new Comment(this, "EBX=multiboot_info "); new Comment(this, "EAX=0x2BADB002 - check if it's really Multiboot loader "); new Comment(this, " ;- copy mb info - some stuff for you "); + new Comment(this, "BEGIN - Multiboot Info"); //new Move { DestinationReg = Registers.ESI, SourceReg = Registers.EBX }; //new Move { DestinationReg = Registers.EDI, SourceRef = ElementReference.New("MultiBootInfo_Structure") }; //new Move { DestinationReg = Registers.ECX, SourceValue = 0x58 }; @@ -56,12 +57,7 @@ namespace Cosmos.IL2CPU.X86 //new Move { DestinationReg = Registers.EBX, SourceRef = ElementReference.New("MultiBootInfo_Structure") }; new Move { DestinationRef = ElementReference.New("MultiBootInfo_Structure"), DestinationIsIndirect = true, SourceReg = Registers.EBX }; new Add { DestinationReg = Registers.EBX, SourceValue = 4 }; - new Move - { - DestinationReg = Registers.EAX, - SourceReg = Registers.EBX, - SourceIsIndirect = true - }; + new Move { DestinationReg = Registers.EAX, SourceReg = Registers.EBX, SourceIsIndirect = true }; new Move { DestinationRef = ElementReference.New("MultiBootInfo_Memory_Low"), DestinationIsIndirect = true, SourceReg = Registers.EAX }; new Add { DestinationReg = Registers.EBX, SourceValue = 4 }; new Move @@ -76,6 +72,8 @@ namespace Cosmos.IL2CPU.X86 DestinationReg = Registers.ESP, SourceRef = ElementReference.New("Kernel_Stack") }; + new Comment(this, "END - Multiboot Info"); + #if LFB_1024_8 new Comment("Set graphics fields"); new Move { DestinationReg = Registers.EBX, SourceRef = ElementReference.New("MultiBootInfo_Structure"), SourceIsIndirect = true }; @@ -86,9 +84,8 @@ namespace Cosmos.IL2CPU.X86 new Move { DestinationReg = Registers.EAX, SourceReg = Registers.EBX, SourceIsIndirect = true, SourceDisplacement = 80 }; new Move { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeMode"), DestinationIsIndirect = true, SourceReg = Registers.EAX }; #endif - new Comment(this, "some more startups todo"); - // SSE init + new Comment(this, "BEGIN - SSE Init"); // CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 new Move { DestinationReg = Registers.EAX, SourceReg = Registers.CR4 }; new Or { DestinationReg = Registers.EAX, SourceValue = 0x100 }; @@ -104,7 +101,7 @@ namespace Cosmos.IL2CPU.X86 new And { DestinationReg = Registers.EAX, SourceValue = 1 }; new Move { DestinationReg = Registers.CR0, SourceReg = Registers.EAX }; - // END SSE INIT + new Comment(this, "END - SSE Init"); if (mComNumber > 0) { @@ -118,7 +115,7 @@ namespace Cosmos.IL2CPU.X86 // Jump to Kernel entry point new Call { DestinationLabel = EntryPointName }; - // After Kernel is done, sit here and halt till next IRQ. + new Comment(this, "Kernel done - loop till next IRQ"); new Label(".loop"); new ClrInterruptFlag(); new Halt(); diff --git a/source2/Kernel/System/Hardware/Core/Cosmos.Core.Plugs/Assemblers/CreateGDT.cs b/source2/Kernel/System/Hardware/Core/Cosmos.Core.Plugs/Assemblers/CreateGDT.cs index f3f74d1e8..39f14f305 100644 --- a/source2/Kernel/System/Hardware/Core/Cosmos.Core.Plugs/Assemblers/CreateGDT.cs +++ b/source2/Kernel/System/Hardware/Core/Cosmos.Core.Plugs/Assemblers/CreateGDT.cs @@ -6,33 +6,104 @@ using CPUx86 = Cosmos.Compiler.Assembler.X86; using System.Collections.Generic; namespace Cosmos.Core.Plugs.Assemblers { - public class CreateGDT : AssemblerMethod { - public override void AssembleNew(object aAssembler, object aMethodInfo) { - var xAssembler = (Assembler)aAssembler; - xAssembler.DataMembers.Add(new CPUAll.DataMember("_NATIVE_GDT_Contents" - , new byte[] - {0,0,0,0,0,0,0,0 // Null Segment - , 0xFF, 0xFF, 0, 0, 0, 0x99, 0xCF, 0 // Code Segment - , 0xFF,0xFF,0,0,0,0x93,0xCF,0})); // Data Segment - xAssembler.DataMembers.Add(new CPUAll.DataMember("_NATIVE_GDT_Pointer", new ushort[] { 0x17, 0, 0 })); + public class CreateGDT : AssemblerMethod { + // http://wiki.osdev.org/Global_Descriptor_Table + // http://http://wiki.osdev.org/GDT_Tutorial + // http://www.osdever.net/bkerndev/Docs/gdt.htm - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceRef = CPUAll.ElementReference.New("_NATIVE_GDT_Pointer") }; - new CPUx86.Move { DestinationRef = CPUAll.ElementReference.New("_NATIVE_GDT_Pointer"), DestinationIsIndirect = true, DestinationDisplacement = 2, SourceRef = CPUAll.ElementReference.New("_NATIVE_GDT_Contents") }; + //TODO: Modify this to support the flags and access as individual input rather + // than requiring user to pass pre-calculated numbers. + protected byte[] Descriptor(UInt32 aBase, UInt32 aSize, bool aCode) { + // Limit is a confusing word. Is it the max physical address or size? + // In fact it is the size, and 286 docs actually refer to it as size + // rather than limit. + // It is also size - 1, else there would be no way to specify + // all of RAM, and a limit of 0 is invalid. - new CPUAll.Label(".RegisterGDT"); - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceRef = CPUAll.ElementReference.New("_NATIVE_GDT_Pointer") }; - new CPUx86.Lgdt { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true }; + var xResult = new byte[8]; + + // Check the limit to make sure that it can be encoded + if ((aSize > 65536) && (aSize & 0x0FFF) != 0x0FFF) { + // If larger than 16 bit, must be an even page (4kb) size + throw new Exception("Invalid size in GDT descriptor."); + } + // Flags nibble + // 7: Granularity + // 0 = bytes + // 1 = 4kb pages + // 6: 1 = 32 bit mode + // 5: 0 - Reserved + // 4: 0 - Reserved + xResult[6] = 0x40; + if (aSize > 65536) { + // Set page sizing instead of byte sizing + aSize = aSize >> 12; + xResult[6] = (byte)(xResult[6] | 0x80); + } + + xResult[0] = (byte)(aSize & 0xFF); + xResult[1] = (byte)((aSize >> 8) & 0xFF); + xResult[6] = (byte)(xResult[6] | ((aSize >> 16) & 0x0F)); - new CPUx86.Move { DestinationReg = CPUx86.Registers.AX, SourceValue = 0x10 }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.DS, SourceReg = CPUx86.Registers.AX }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.ES, SourceReg = CPUx86.Registers.AX }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.FS, SourceReg = CPUx86.Registers.AX }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.GS, SourceReg = CPUx86.Registers.AX }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.SS, SourceReg = CPUx86.Registers.AX }; + xResult[2] = (byte)(aBase & 0xFF); + xResult[3] = (byte)((aBase >> 8) & 0xFF); + xResult[4] = (byte)((aBase >> 16) & 0xFF); + xResult[7] = (byte)((aBase >> 24) & 0xFF); - // Force reload of code segment - new CPUx86.JumpToSegment { Segment = 8, DestinationLabel = "flush__GDT__table" }; - new CPUAll.Label("flush__GDT__table"); - } + xResult[5] = (byte)( + // Bit 7: Present, must be 1 + 0x80 | + // Bit 6-5: Privilege, 0=kernel, 3=user + 0x00 | + // Reserved, must be 1 + 0x10 | + // Bit 3: 1=Code, 0=Data + (aCode ? 0x08 : 0x00) | + // Bit 2: Direction/Conforming + 0x00 | + // Bit 1: R/W Data (1=Writeable, 0=Read only) Code (1=Readable, 0=Not readable) + 0x02 | + // Bit 0: Accessed - Set to 0. Updated by CPU later. + 0x00 + ); + + return xResult; } + + public override void AssembleNew(object aAssembler, object aMethodInfo) { + var xAsm = (Assembler)aAssembler; + + var xGDT = new List(); + // Null Segment - Selector 0x00 + // Not used, but required by many emulators. + xGDT.AddRange(new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + // Code Segment + byte xCodeSelector = (byte)xGDT.Count; + xGDT.AddRange(Descriptor(0x00000000, 0xFFFFFFFF, true)); + // Data Segment - Selector 0x0B + byte xDataSelector = (byte)xGDT.Count; + xGDT.AddRange(Descriptor(0x00000000, 0xFFFFFFFF, false)); + xAsm.DataMembers.Add(new CPUAll.DataMember("_NATIVE_GDT_Contents", xGDT.ToArray())); + + xAsm.DataMembers.Add(new CPUAll.DataMember("_NATIVE_GDT_Pointer", new ushort[] { 0x17, 0, 0 })); + + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceRef = CPUAll.ElementReference.New("_NATIVE_GDT_Pointer") }; + new CPUx86.Move { DestinationRef = CPUAll.ElementReference.New("_NATIVE_GDT_Pointer"), DestinationIsIndirect = true, DestinationDisplacement = 2, SourceRef = CPUAll.ElementReference.New("_NATIVE_GDT_Contents") }; + + new CPUAll.Label(".RegisterGDT"); + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceRef = CPUAll.ElementReference.New("_NATIVE_GDT_Pointer") }; + new CPUx86.Lgdt { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true }; + + new CPUx86.Move { DestinationReg = CPUx86.Registers.AX, SourceValue = 0x10 }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.DS, SourceReg = CPUx86.Registers.AX }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.ES, SourceReg = CPUx86.Registers.AX }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.FS, SourceReg = CPUx86.Registers.AX }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.GS, SourceReg = CPUx86.Registers.AX }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.SS, SourceReg = CPUx86.Registers.AX }; + + new CPUAll.Comment("Force reload of code segment"); + new CPUx86.JumpToSegment { Segment = 0x08, DestinationLabel = "flush__GDT__table" }; + new CPUAll.Label("flush__GDT__table"); + } + } }