--- /dev/null
+/*
+ * General data structures and routines for segmentation
+ * Copyright (c) 2001, David H. Hovemeyer <daveho@cs.umd.edu>
+ * $Revision: 1.1 $
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "COPYING".
+ */
+
+/*
+ * Source: _Protected Mode Software Architecture_ by Tom Shanley,
+ * ISBN 020155447X.
+ */
+
+#include <geekos/kassert.h>
+#include <geekos/string.h>
+#include <geekos/tss.h>
+#include <geekos/segment.h>
+
+static __inline__ void Set_Size_And_Base_Pages(
+ struct Segment_Descriptor* desc,
+ ulong_t baseAddr,
+ ulong_t numPages
+)
+{
+ /*
+ * There are 20 bits in the size fields of a segment descriptor.
+ * The maximum possible value is thus 0xFFFFF, which in terms of
+ * pages is one page less than 4GB. So, I conclude that the
+ * number of pages in the segment is one greater than the
+ * value specified in the descriptor.
+ */
+ KASSERT(numPages > 0);
+ numPages -= 1;
+
+ desc->sizeLow = numPages & 0xFFFF;
+ desc->sizeHigh = (numPages >> 16) & 0x0F;
+ desc->baseLow = baseAddr & 0xFFFFFF;
+ desc->baseHigh = (baseAddr >> 24) & 0xFF;
+ desc->granularity = 1; /* size in pages */
+}
+
+static __inline__ void Set_Size_And_Base_Bytes(
+ struct Segment_Descriptor* desc,
+ ulong_t baseAddr,
+ ulong_t numBytes
+)
+{
+ desc->sizeLow = numBytes & 0xFFFF;
+ desc->sizeHigh = (numBytes >> 16) & 0x0F;
+ desc->baseLow = baseAddr & 0xFFFFFF;
+ desc->baseHigh = (baseAddr >> 24) & 0xFF;
+ desc->granularity = 0; /* size in bytes */
+}
+
+/*
+ * Initialize an unused segment descriptor.
+ */
+void Init_Null_Segment_Descriptor(struct Segment_Descriptor* desc)
+{
+ memset(desc, '\0', sizeof(*desc));
+}
+
+/*
+ * Initialize a code segment descriptor.
+ */
+void Init_Code_Segment_Descriptor(
+ struct Segment_Descriptor* desc,
+ ulong_t baseAddr,
+ ulong_t numPages,
+ int privilegeLevel
+)
+{
+ KASSERT(privilegeLevel >= 0 && privilegeLevel <= 3);
+
+ Set_Size_And_Base_Pages(desc, baseAddr, numPages);
+ desc->type = 0x0A; /* 1010b: code, !conforming, readable, !accessed */
+ desc->system = 1;
+ desc->dpl = privilegeLevel;
+ desc->present = 1;
+ desc->reserved = 0;
+ desc->dbBit = 1; /* 32 bit code segment */
+}
+
+/*
+ * Initialize a data segment descriptor.
+ */
+void Init_Data_Segment_Descriptor(
+ struct Segment_Descriptor* desc,
+ ulong_t baseAddr,
+ ulong_t numPages,
+ int privilegeLevel
+)
+{
+ KASSERT(privilegeLevel >= 0 && privilegeLevel <= 3);
+
+ Set_Size_And_Base_Pages(desc, baseAddr, numPages);
+ desc->type = 0x02; /* 0010b: data, expand-up, writable, !accessed */
+ desc->system = 1;
+ desc->dpl = privilegeLevel;
+ desc->present = 1;
+ desc->reserved = 0;
+ desc->dbBit = 1; /* 32 bit operands */
+}
+
+/*
+ * Initialize a TSS descriptor.
+ */
+void Init_TSS_Descriptor(struct Segment_Descriptor* desc, struct TSS* theTSS)
+{
+ Set_Size_And_Base_Bytes(desc, (ulong_t) theTSS, sizeof(struct TSS));
+ desc->type = 0x09; /* 1001b: 32 bit, !busy */
+ desc->system = 0;
+ desc->dpl = 0;
+ desc->present = 1;
+ desc->reserved = 0;
+ desc->dbBit = 0; /* must be 0 in TSS */
+}
+
+/*
+ * Initialize an LDT (Local Descriptor Table) descriptor.
+ */
+void Init_LDT_Descriptor(
+ struct Segment_Descriptor* desc,
+ struct Segment_Descriptor theLDT[],
+ int numEntries
+)
+{
+ Set_Size_And_Base_Bytes(
+ desc, (ulong_t) theLDT, sizeof(struct Segment_Descriptor) * numEntries);
+
+ desc->type = 0x02; /* 0010b */
+ desc->system = 0;
+ desc->dpl = 0;
+ desc->present = 1;
+ desc->reserved = 0;
+ desc->dbBit = 0;
+}