aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon duSaint2022-05-03 16:36:47 -0700
committerJon duSaint2022-05-03 16:36:47 -0700
commit7c75c02f784be12343e2e4f82726f3a5f0ddb6a7 (patch)
treece0bea4ad2f88a77392efaf3d3c3b66a547f8459
parent88753ad637bec0c665a611be6e703a519b0660ad (diff)

Marmot: add old project

-rw-r--r--Marmot/Makefile49
-rw-r--r--Marmot/alloc.c352
-rw-r--r--Marmot/apic.c53
-rw-r--r--Marmot/basic_font.hex256
-rw-r--r--Marmot/boot.S331
-rw-r--r--Marmot/cpu.c64
-rw-r--r--Marmot/cpu.h186
-rw-r--r--Marmot/cs.pl35
-rw-r--r--Marmot/cursor.xbm31
-rw-r--r--Marmot/device.c19
-rw-r--r--Marmot/dumpRegs.vp476
-rw-r--r--Marmot/font.S776
-rw-r--r--Marmot/forth.c23
-rw-r--r--Marmot/hexfont2data.pl87
-rw-r--r--Marmot/interrupts.S126
-rw-r--r--Marmot/irq.c711
-rw-r--r--Marmot/ld.conf26
-rw-r--r--Marmot/loader.S957
-rw-r--r--Marmot/marmot.bmpbin0 -> 1920054 bytes
-rw-r--r--Marmot/marmot.h366
-rw-r--r--Marmot/marmot_os.xcf.bz2bin0 -> 904457 bytes
-rw-r--r--Marmot/mksym.pl30
-rw-r--r--Marmot/mm.c1064
-rw-r--r--Marmot/panic.c96
-rw-r--r--Marmot/pci.c343
-rw-r--r--Marmot/task.c179
-rw-r--r--Marmot/types.h44
-rw-r--r--Marmot/util.S122
-rw-r--r--Marmot/vesa.S420
-rw-r--r--Marmot/video.c562
-rw-r--r--Marmot/window.c37
-rw-r--r--README4
32 files changed, 7825 insertions, 0 deletions
diff --git a/Marmot/Makefile b/Marmot/Makefile
new file mode 100644
index 0000000..c834095
--- /dev/null
+++ b/Marmot/Makefile
@@ -0,0 +1,49 @@
+# Makefile for Marmot
+
+CC = /usr/bin/gcc
+LD = /usr/bin/ld
+PERL = /usr/bin/perl
+
+ASFLAGS = -Wa,--fatal-warnings
+CFLAGS = -Wall -O2 -ffreestanding -funsigned-char -fno-common -I. -I.
+LDFLAGS = -Map link.map --script=ld.conf
+
+SFILES = boot.S loader.S interrupts.S vesa.S font.S util.S
+CFILES = mm.c video.c irq.c task.c apic.c cpu.c pci.c alloc.c panic.c
+
+
+.PHONY : all
+all : marmot.iso
+
+# Run this rule manually - should never need to be done
+.PHONY : fonts
+fonts :
+ $(PERL) hexfont2data.pl basic_font.hex font.S
+
+marmot.iso : boot.img
+ mkdir -p iso_files
+ cp -f boot.img marmot.bmp iso_files/
+ genisoimage -b boot.img -o marmot.iso iso_files
+
+boot.img : boot
+ $(PERL) mksym.pl
+ dd if=/dev/urandom of=$@ bs=512 count=2880
+ dd if=boot of=$@ bs=512 seek=0 conv=notrunc
+ $(PERL) cs.pl
+
+boot : $(SFILES:.S=.o) $(CFILES:.c=.o)
+ $(LD) $^ $(LDFLAGS) -o $@
+
+.PHONY : asm
+asm : $(CFILES:.c=.s)
+
+%.o : %.S
+ $(CC) $(CFLAGS) $(ASFLAGS) -c -o $@ $<
+
+%.s : %.c
+ $(CC) $(CFLAGS) -S $<
+
+.PHONY : clean
+clean :
+ rm -fr iso_files
+ rm -f boot boot.img marmot.iso link.map symbols.txt *.s *.o *~
diff --git a/Marmot/alloc.c b/Marmot/alloc.c
new file mode 100644
index 0000000..e202709
--- /dev/null
+++ b/Marmot/alloc.c
@@ -0,0 +1,352 @@
+/*
+ * alloc.c --
+ *
+ * Allocate memory of arbitrary sizes.
+ *
+ * The mechanism of allocation used here is that large, CHUNK_SIZE
+ * sized blocks of memory are requested from the system. They are
+ * kept track of by overlaying the first sizeof(struct SysBlock)
+ * bytes with a struct SysBlock and having the next pointer point
+ * to the next block, or being NULL. That way, when Free is
+ * called, the linked list, kept in the variable memory, is walked
+ * and each node is free'd. Each block is then carved up into
+ * smaller blocks. Each of these smaller blocks has the first
+ * sizeof(MemHeader) bytes overlaid by a struct MemHeader.
+ * Then, if one of the smaller blocks is needed, the struct
+ * MemHeader is placed on the alloc list. If, relative to the
+ * size of the memory request, it is fairly large, it is
+ * partitioned into two blocks. One is placed on the alloc list
+ * and returned to the caller; the other is placed on the free
+ * list. Then, as space is needed, adjacent free blocks are
+ * merged to create larger blocks.
+ */
+
+
+#include <marmot.h>
+
+
+/* the default amount of memory to request from the system each time */
+#define DEFAULT_CHUNK_SIZE PAGE_SIZE
+
+/* round an amount of memory to the next page size up */
+#define ROUND_TO_PAGE_SIZE(a) (((a) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
+
+/* the minimum size of housekeeping info in a sys block */
+#define ALLOC_ADJUST (sizeof(struct SysBlock) + sizeof(struct MemHeader))
+
+/* the smallest amount which will be returned */
+#define MIN_ALLOC_AMOUNT 8
+
+/* the largest amount that can be handled at one time */
+#define MAX_ALLOC_AMOUNT (chunkSize - ALLOC_ADJUST)
+
+
+/* header for a block of memory - this is what is referenced on
+ both the alloc and free lists */
+struct MemHeader {
+ /* size of the chunk, not including the header */
+ uint64 size;
+ struct MemHeader *next;
+} __attribute__((packed));
+
+
+/* header for the block returned by a call to PageAlloc */
+struct SysBlock {
+ struct SysBlock *next;
+} __attribute__((packed));
+
+
+/* the free list */
+static struct MemHeader *freeList = NULL;
+
+/* the alloc list */
+static struct MemHeader *allocList = NULL;
+
+/* the list of malloc'ed blocks */
+static struct SysBlock *memory;
+
+/* the allocation size for memory chunks */
+static uint64 chunkSize;
+
+/* whether or not memory is fragmented */
+static Bool freeListNeedsCompacting = 0;
+
+/* forward declaration needed for mem_trace */
+void CompactFreeList(void);
+
+
+/*
+ * FreeListInsertSorted --
+ *
+ * Insert NEW onto the free list, sorted numerically by address.
+ */
+
+void
+FreeListInsertSorted(struct MemHeader *new)
+{
+ struct MemHeader *freeTmp = freeList;
+
+ /* check for empty list */
+ if (freeList == NULL) {
+ freeList = new;
+ freeList->next = NULL;
+ return;
+ }
+
+ /* if NEW is the lowest address */
+ if (new < freeTmp) {
+ new->next = freeTmp;
+ freeList = new;
+ return;
+ }
+
+ /* general case - find the insertion point */
+ while (freeTmp->next != NULL) {
+ if (new < freeTmp->next) {
+ break;
+ }
+ freeTmp = freeTmp->next;
+ }
+
+ new->next = freeTmp->next;
+ freeTmp->next = new;
+}
+
+
+/*
+ * CompactFreeList --
+ *
+ * Defragment memory by merging all adjacent free blocks.
+ */
+
+void
+CompactFreeList(void)
+{
+ struct MemHeader *freeTmp = freeList;
+
+ /*
+ * Search through the free list for adjacent blocks - if two are
+ * adjacent, then merge them to create a larger block.
+ */
+
+ while (freeTmp != NULL) {
+ if (freeTmp->next == NULL) {
+ /* at the end of the list */
+ break;
+ }
+
+ /* if two free blocks are adjacent */
+ if ((void *)freeTmp + freeTmp->size + sizeof(struct MemHeader) ==
+ (void *)freeTmp->next) {
+
+ /* merge them */
+ freeTmp->size += freeTmp->next->size + sizeof(struct MemHeader);
+ freeTmp->next = freeTmp->next->next;
+
+ continue; /* try again with this same block */
+ }
+
+ freeTmp = freeTmp->next;
+ }
+
+ freeListNeedsCompacting = FALSE;
+}
+
+
+/*
+ * MemInit --
+ *
+ * Called when Alloc is first invoked. Sets up the necessary
+ * data structures.
+ */
+
+void
+AllocInit(void)
+{
+ chunkSize = DEFAULT_CHUNK_SIZE;
+
+ /* set up the system list */
+ memory = (void *)RegionAlloc(MM_VA_HEAP, chunkSize / PAGE_SIZE, MM_RW);
+ memory->next = NULL;
+
+ /* set up the free list */
+ freeList = (void *)memory + sizeof(struct SysBlock);
+ freeList->size = (chunkSize - sizeof(struct SysBlock) -
+ sizeof(struct MemHeader));
+ freeList->next = NULL;
+}
+
+
+/*
+ * Alloc --
+ *
+ * Allocate AMOUNT bytes of memory and return it with all of its
+ * bytes zeroed.
+ */
+
+void *
+alloc(size_t amount)
+{
+ struct MemHeader *freeTmp, *last, *retBlock;
+ struct SysBlock *sysTmp;
+
+ if (amount == 0) {
+ return NULL;
+ }
+
+ chunkSize = DEFAULT_CHUNK_SIZE;
+
+ /* if more than the default chunk size was requested */
+ if (amount > MAX_ALLOC_AMOUNT) {
+ chunkSize = amount + ALLOC_ADJUST;
+ }
+
+ chunkSize = ROUND_TO_PAGE_SIZE(chunkSize);
+
+ if (freeList == NULL && allocList == NULL) {
+ AllocInit();
+ }
+
+ /* don't allocate less than MIN_ALLOC_AMOUNT */
+ if (amount < MIN_ALLOC_AMOUNT) {
+ amount = MIN_ALLOC_AMOUNT;
+ }
+
+
+ /* loop until a block is found */
+ while (TRUE) {
+ /* first walk the free list, looking for the correct size */
+ last = NULL;
+ freeTmp = freeList;
+
+ while (freeTmp != NULL) {
+ if (freeTmp->size >= amount) {
+ goto GOT_FREE_BLOCK;
+ }
+
+ last = freeTmp;
+ freeTmp = freeTmp->next;
+ }
+
+
+ /*
+ * Didn't find a free block of the right size - try compacting
+ * the free list.
+ */
+ if (freeListNeedsCompacting) {
+ CompactFreeList();
+ continue;
+ }
+
+ /* if we got here, then we need to allocate a new chunk */
+
+ /* find the last chunk */
+ sysTmp = memory;
+ while (sysTmp->next != NULL) {
+ sysTmp = sysTmp->next;
+ }
+
+ /* alloc a new chunk and save its ptr */
+ sysTmp->next = (void *)RegionAlloc(MM_VA_HEAP,
+ chunkSize / PAGE_SIZE, MM_RW);
+ sysTmp->next->next = NULL;
+
+ /* create the new free block */
+ freeTmp = (void *)sysTmp->next + sizeof(struct SysBlock);
+ freeTmp->next = NULL;
+ freeTmp->size = chunkSize - ALLOC_ADJUST;
+
+ /* put that bad boy in the free list */
+ FreeListInsertSorted(freeTmp);
+
+ /* with this new large chunk, try again */
+ }
+
+ GOT_FREE_BLOCK:
+ /* remove the block from the free list */
+ if (last == NULL) {
+ freeList = freeTmp->next;
+ } else {
+ last->next = freeTmp->next;
+ }
+
+ retBlock = freeTmp;
+
+
+ /* shrink the block, if possible */
+ if (retBlock->size >
+ amount + sizeof(struct MemHeader) + MIN_ALLOC_AMOUNT) {
+ struct MemHeader *new = ((void *)retBlock + sizeof(struct MemHeader) +
+ amount);
+
+ new->size = retBlock->size - sizeof (struct MemHeader) - amount;
+ new->next = NULL;
+ retBlock->size = amount;
+
+ FreeListInsertSorted(new);
+ }
+
+ /* put it on the alloc list */
+ retBlock->next = allocList;
+ allocList = retBlock;
+
+
+ /* and (finally) return the memory */
+ bzero((void *)retBlock + sizeof(struct MemHeader), amount);
+ return ((void *)retBlock + sizeof(struct MemHeader));
+}
+
+/*
+ * Free --
+ *
+ * Add FREEMEM to the free list.
+ *
+ */
+
+void
+free(void *freemem)
+{
+ struct MemHeader *mem;
+ struct MemHeader *tmp = allocList, *last = NULL;
+
+ if (freemem == NULL) {
+ return;
+ }
+
+ mem = freemem - sizeof(struct MemHeader);
+
+ /* find FREEMEM on the alloc list */
+ while (tmp != NULL) {
+ if (tmp == mem) break;
+
+ last = tmp;
+ tmp = tmp->next;
+ }
+
+ /* remove from the alloc list */
+ if (last == NULL) {
+ allocList = tmp->next;
+ } else {
+ last->next = tmp->next;
+ }
+
+ /* put it on the free list */
+ FreeListInsertSorted(mem);
+ freeListNeedsCompacting = TRUE;
+}
+
+
+void *
+realloc(void *mem, size_t amt)
+{
+ void *new;
+
+ new = alloc(amt);
+
+ if (new != NULL) {
+ bcopy(mem, new, amt);
+ free(mem);
+ }
+
+ return new;
+}
diff --git a/Marmot/apic.c b/Marmot/apic.c
new file mode 100644
index 0000000..d3dbee4
--- /dev/null
+++ b/Marmot/apic.c
@@ -0,0 +1,53 @@
+/*
+ * apic.c
+ *
+ * Check for APIC support and initialize external interrupts to use it.
+ */
+
+#include <marmot.h>
+
+Bool usingAPIC;
+
+void
+InitPIC(void)
+{
+ usingAPIC = FALSE;
+}
+
+VA apicBase, ioapicBase;
+
+/* uint64 tval, tval2; */
+
+void
+InitAPIC(void)
+{
+ uint64 apicBaseReg;
+ char deviceName[] = {'l', 'a', 'p', 'i', 'c', 0, 0, 0, 0};
+
+ if (!CPU_GetFeature(CPU_APIC_ENABLED)) {
+ InitPIC();
+ return;
+ }
+
+ usingAPIC = TRUE;
+
+ rdmsr(APIC_BASE_MSR, apicBaseReg);
+/* VPROBE_TEST(APIC_BASE_MSR, apicBaseReg); */
+
+ apicBase = (VA)(apicBaseReg & 0x000ffffffffff000);
+ if (apicBase & (1 << 8)) {
+ deviceName[5] = 'B';
+ deviceName[6] = 'S';
+ deviceName[7] = 'P';
+ } else {
+ deviceName[5] = 'A';
+ deviceName[6] = 'P';
+ }
+
+ MapIORegion((PA)apicBase, (PA)apicBase + PAGE_SIZE, deviceName);
+
+ /* init IO APIC (part of chipset) */
+ ioapicBase = (VA)0xfec00000; // real address is in APICBASE on chipset
+
+
+}
diff --git a/Marmot/basic_font.hex b/Marmot/basic_font.hex
new file mode 100644
index 0000000..2f1a314
--- /dev/null
+++ b/Marmot/basic_font.hex
@@ -0,0 +1,256 @@
+0000:AAAA00018000000180004A51EA505A51C99E0001800000018000000180005555
+0001:AAAA00018000000180003993C252325F8A527193800000018000000180005555
+0002:AAAA00018000000180003BA5C124311989247125800000018000000180005555
+0003:AAAA00018000000180007BA5C1247919C1247925800000018000000180005555
+0004:AAAA000180000001800079BFC2487A49C2487989800000018000000180005555
+0005:AAAA00018000000180007A4DC2527B53C2D67A4F800000018000000180005555
+0006:AAAA000180000001800031A5CA287A31CA2849A5800000018000000180005555
+0007:AAAA000180000001800073D1CA1073D1CA1073DF800000018000000180005555
+0008:AAAA000180000001800078E1C50078C1C42079C1800000018000000180005555
+0009:AAAA000180000001800045F1C4407C41C4404441800000018000000180005555
+000A:AAAA000180000001800041F1C10041F1C1007D01800000018000000180005555
+000B:AAAA000180000001800045F1C4404441A8401041800000018000000180005555
+000C:AAAA00018000000180007DF1C1007DF1C1004101800000018000000180005555
+000D:AAAA00018000000180003DE1C11041E1C1203D11800000018000000180005555
+000E:AAAA00018000000180003CE1C1103911851078E1800000018000000180005555
+000F:AAAA00018000000180003DF1C0403841844079F1800000018000000180005555
+0010:AAAA00018000000180007239CA204A39CA2073B9800000018000000180005555
+0011:AAAA00018000000180007189CA184A09CA08719D800000018000000180005555
+0012:AAAA00018000000180007199CA044A09CA10719D800000018000000180005555
+0013:AAAA00018000000180007199CA044A19CA047199800000018000000180005555
+0014:AAAA00018000000180007185CA0C4A15CA1C7185800000018000000180005555
+0015:AAAA00018000000180004993EA546A59DBD44A53800000018000000180005555
+0016:AAAA00018000000180003453C29A311789127113800000018000000180005555
+0017:AAAA00018000000180007BB9C1247939C1247939800000018000000180005555
+0018:AAAA00018000000180003325C4B447ADC4A434A5800000018000000180005555
+0019:AAAA00018000000180007D11C1B07D51C1107D11800000018000000180005555
+001A:AAAA00018000000180003A5DC252325D8A52719D800000018000000180005555
+001B:AAAA000180000001800079CFC2107991C0507B8F800000018000000180005555
+001C:AAAA000180000001800079C1C2007981C0404381800000018000000180005555
+001D:AAAA000180000001800039C1C2005981C8403B81800000018000000180005555
+001E:AAAA000180000001800071C1CA007181D0404B81800000018000000180005555
+001F:AAAA000180000001800049C1CA004981C8403381800000018000000180005555
+0020:00000000000000000000000000000000
+0021:00000000080808080808080008080000
+0022:00002222222200000000000000000000
+0023:000000001212127E24247E4848480000
+0024:00000000083E4948380E09493E080000
+0025:00000000314A4A340808162929460000
+0026:000000001C2222221C39454246390000
+0027:00000808080800000000000000000000
+0028:00000004080810101010101008080400
+0029:00000020101008080808080810102000
+002A:00000000000008492A1C2A4908000000
+002B:0000000000000808087F080808000000
+002C:00000000000000000000000018080810
+002D:0000000000000000007E000000000000
+002E:00000000000000000000000018180000
+002F:00000000020204080810102040400000
+0030:00000000182442424242424224180000
+0031:000000000818280808080808083E0000
+0032:000000003C4242020C102040407E0000
+0033:000000003C4242021C020242423C0000
+0034:00000000040C142444447E0404040000
+0035:000000007E4040407C020202423C0000
+0036:000000001C2040407C424242423C0000
+0037:000000007E0202040404080808080000
+0038:000000003C4242423C424242423C0000
+0039:000000003C4242423E02020204380000
+003A:00000000000018180000001818000000
+003B:00000000000018180000001808081000
+003C:00000000000204081020100804020000
+003D:000000000000007E0000007E00000000
+003E:00000000004020100804081020400000
+003F:000000003C4242020408080008080000
+0040:000000001C224A565252524E201E0000
+0041:0000000018242442427E424242420000
+0042:000000007C4242427C424242427C0000
+0043:000000003C42424040404042423C0000
+0044:00000000784442424242424244780000
+0045:000000007E4040407C404040407E0000
+0046:000000007E4040407C40404040400000
+0047:000000003C424240404E4242463A0000
+0048:00000000424242427E42424242420000
+0049:000000003E08080808080808083E0000
+004A:000000001F0404040404044444380000
+004B:00000000424448506060504844420000
+004C:000000004040404040404040407E0000
+004D:00000000424266665A5A424242420000
+004E:0000000042626252524A4A4646420000
+004F:000000003C42424242424242423C0000
+0050:000000007C4242427C40404040400000
+0051:000000003C4242424242425A663C0300
+0052:000000007C4242427C48444442420000
+0053:000000003C424240300C0242423C0000
+0054:000000007F0808080808080808080000
+0055:000000004242424242424242423C0000
+0056:00000000414141222222141408080000
+0057:00000000424242425A5A666642420000
+0058:00000000424224241818242442420000
+0059:00000000414122221408080808080000
+005A:000000007E02020408102040407E0000
+005B:0000000E080808080808080808080E00
+005C:00000000404020101008080402020000
+005D:00000070101010101010101010107000
+005E:00001824420000000000000000000000
+005F:00000000000000000000000000007F00
+0060:00201008000000000000000000000000
+0061:0000000000003C42023E4242463A0000
+0062:0000004040405C6242424242625C0000
+0063:0000000000003C4240404040423C0000
+0064:0000000202023A4642424242463A0000
+0065:0000000000003C42427E4040423C0000
+0066:0000000C1010107C1010101010100000
+0067:0000000000023A44444438203C42423C
+0068:0000004040405C624242424242420000
+0069:000000080800180808080808083E0000
+006A:0000000404000C040404040404044830
+006B:00000000404044485060504844420000
+006C:000000001808080808080808083E0000
+006D:00000000000076494949494949490000
+006E:0000000000005C624242424242420000
+006F:0000000000003C4242424242423C0000
+0070:0000000000005C6242424242625C4040
+0071:0000000000003A4642424242463A0202
+0072:0000000000005C624240404040400000
+0073:0000000000003C4240300C02423C0000
+0074:0000000010107C1010101010100C0000
+0075:000000000000424242424242463A0000
+0076:00000000000042424224242418180000
+0077:00000000000041494949494949360000
+0078:00000000000042422418182442420000
+0079:0000000000004242424242261A02023C
+007A:0000000000007E0204081020407E0000
+007B:0000000C101008081010080810100C00
+007C:00000808080808080808080808080808
+007D:00000030080810100808101008083000
+007E:00000031494600000000000000000000
+007F:AAAA000180000001800073D1CA104BD1CA1073DF800000018000000180005555
+0080:AAAA0001800000018000719DCA5273D3C252425D800000018000000180005555
+0081:AAAA0001800000018000499DCA527A5DCA504991800000018000000180005555
+0082:AAAA00018000000180007393CA52739FCA127213800000018000000180005555
+0083:AAAA00018000000180004B93EA525B9FCA524B93800000018000000180005555
+0084:AAAA000180000001800074B9A6A425A5A4A474B9800000018000000180005555
+0085:AAAA00018000000180004BD1EA105BD1CA104BDF800000018000000180005555
+0086:AAAA000180000001800039CDC212319F88527393800000018000000180005555
+0087:AAAA000180000001800079CDC212799FC0527B93800000018000000180005555
+0088:AAAA00018000000180004B9DC9207919C9044939800000018000000180005555
+0089:AAAA00018000000180004BB9C9087909C9084931800000018000000180005555
+008A:AAAA000180000001800045CDC4904489A8841099800000018000000180005555
+008B:AAAA0001800000018000721DCA127213C21243DD800000018000000180005555
+008C:AAAA00018000000180007213CA127213C21243CD800000018000000180005555
+008D:AAAA00018000000180000E2189200E218A200921800000018000000180005555
+008E:AAAA000180000001800039DDC202318D8850739F800000018000000180005555
+008F:AAAA000180000001800039DDC202318D8842739D800000018000000180005555
+0090:AAAA000180000001800071CFCA104A0DCA0271DD800000018000000180005555
+0091:AAAA00018000000180007245CA4C7245C244418F800000018000000180005555
+0092:AAAA0001800000018000725DCA42724DC250419F800000018000000180005555
+0093:AAAA00018000000180003B9DC120311989047139800000018000000180005555
+0094:AAAA000180000001800039D3C212421FC21239D3800000018000000180005555
+0095:AAAA00018000000180004511ED105551C5B04511800000018000000180005555
+0096:AAAA00018000000180003B8DC252339F8A127213800000018000000180005555
+0097:AAAA00018000000180007B8DC2527B9FC2127A13800000018000000180005555
+0098:AAAA0001800000018000398FC250324D8A42719D800000018000000180005555
+0099:AAAA0001800000018000339BC42225A394A2639B800000018000000180005555
+009A:AAAA000180000001800039DDC20832098A0871DD800000018000000180005555
+009B:AAAA000180000001800039DDC2084189C0483B9D800000018000000180005555
+009C:AAAA00018000000180000EF990200C2182201C21800000018000000180005555
+009D:AAAA000180000001800031CFCA104991C850338F800000018000000180005555
+009E:AAAA00018000000180007221CB6072A1C2204221800000018000000180005555
+009F:AAAA0001800000018000338FCA507B91CA104A0F800000018000000180005555
+00A0:00000000000000000000000000000000
+00A1:00000000080800080808080808080000
+00A2:0000000008083E494848493E08080000
+00A3:000000000E1010107C1010103E610000
+00A4:000000000042243C24243C2442000000
+00A5:00000000412214087F087F0808080000
+00A6:00000000080808080000080808080000
+00A7:000000003C42403C42423C02423C0000
+00A8:24240000000000000000000000000000
+00A9:000000003C4299A5A1A1A599423C0000
+00AA:00001C021E221E003E00000000000000
+00AB:00000000001212242448242412120000
+00AC:000000000000000000007E0202020000
+00AD:0000000000000000007E000000000000
+00AE:000000003C42B9A5A5B9A9A5423C0000
+00AF:00007E00000000000000000000000000
+00B0:10282810000000000000000000000000
+00B1:000000000808087F080808007F000000
+00B2:00001C22021C20203E00000000000000
+00B3:00001C22021C02221C00000000000000
+00B4:00040810000000000000000000000000
+00B5:000000000000000022222222362A2020
+00B6:0000003E7A7A7A7A3A0A0A0A0A0A0E00
+00B7:00000000000000001818000000000000
+00B8:00000000000000000000000000000830
+00B9:00000818280808080800000000000000
+00BA:00001C2222221C003E00000000000000
+00BB:00000000004848242412242448480000
+00BC:00000000226224282812162A4E420000
+00BD:000000002262242828141A22444E0000
+00BE:00000000621224186812162A4E420000
+00BF:000000000808000808304242423C0000
+00C0:300C000018242442427E424242420000
+00C1:0C30000018242442427E424242420000
+00C2:1824000018242442427E424242420000
+00C3:324C000018242442427E424242420000
+00C4:2424000018242442427E424242420000
+00C5:1824180018242442427E424242420000
+00C6:000000001F2848487F484848484F0000
+00C7:000000003C42424040404042423C0830
+00C8:300C00007E4040407C404040407E0000
+00C9:0C3000007E4040407C404040407E0000
+00CA:182400007E4040407C404040407E0000
+00CB:242400007E4040407C404040407E0000
+00CC:180600003E08080808080808083E0000
+00CD:0C3000003E08080808080808083E0000
+00CE:182400003E08080808080808083E0000
+00CF:242400003E08080808080808083E0000
+00D0:0000000078444242F242424244780000
+00D1:324C000042626252524A4A4646420000
+00D2:300C00003C42424242424242423C0000
+00D3:0C3000003C42424242424242423C0000
+00D4:182400003C42424242424242423C0000
+00D5:324C00003C42424242424242423C0000
+00D6:242400003C42424242424242423C0000
+00D7:00000000000000422418244200000000
+00D8:000000023A44464A4A525262225C4000
+00D9:300C00004242424242424242423C0000
+00DA:0C3000004242424242424242423C0000
+00DB:182400004242424242424242423C0000
+00DC:242400004242424242424242423C0000
+00DD:0C300000414122221408080808080000
+00DE:00000040407844424244784040400000
+00DF:00000000384444447C424242625C0000
+00E0:0000300C00003C42023E4242463A0000
+00E1:00000C3000003C42023E4242463A0000
+00E2:0000182400003C42023E4242463A0000
+00E3:0000324C00003C42023E4242463A0000
+00E4:0000242400003C42023E4242463A0000
+00E5:0018241800003C42023E4242463A0000
+00E6:0000000000003E49093F4848493E0000
+00E7:0000000000003C4240404040423C0830
+00E8:0000300C00003C42427E4040423C0000
+00E9:00000C3000003C42427E4040423C0000
+00EA:0000182400003C42427E4040423C0000
+00EB:0000242400003C42427E4040423C0000
+00EC:0000300C0000180808080808083E0000
+00ED:00000C300000180808080808083E0000
+00EE:000018240000180808080808083E0000
+00EF:000024240000180808080808083E0000
+00F0:0000320C1422023E42424242423C0000
+00F1:0000324C00005C624242424242420000
+00F2:0000300C00003C4242424242423C0000
+00F3:00000C3000003C4242424242423C0000
+00F4:0000182400003C4242424242423C0000
+00F5:0000324C00003C4242424242423C0000
+00F6:0000242400003C4242424242423C0000
+00F7:0000000000001800007E000018000000
+00F8:0000000000023C464A4A5252623C4000
+00F9:0000300C0000424242424242463A0000
+00FA:00000C300000424242424242463A0000
+00FB:000018240000424242424242463A0000
+00FC:000024240000424242424242463A0000
+00FD:00000C3000004242424242261A02023C
+00FE:0000000020203C222222242830202020
+00FF:0000242400004242424242261A02023C
diff --git a/Marmot/boot.S b/Marmot/boot.S
new file mode 100644
index 0000000..2e73d14
--- /dev/null
+++ b/Marmot/boot.S
@@ -0,0 +1,331 @@
+ /* boot loader for Marmot */
+
+ /* 2k stack starting at 0x6000 */
+#define BOOT_SS 0x400
+#define BOOT_SP 0x2000
+
+#define LOADER_START 0x8000
+
+
+ .section .boot, "xa"
+
+ .code16
+ .global _start
+_start: jmp around
+
+
+ /* BIOS parameter block */
+
+ .org 3
+oem_signature:
+ .ascii "=marmot="
+
+ /* DOSv2 */
+sector_size:
+ .word 512
+sectors_per_allocation_unit:
+ .byte 2
+reserved_sectors:
+ .word 2
+fat_count:
+ .byte 0
+record_count:
+ .word 2
+sectors_in_volume:
+ .word 2880
+media_descriptor:
+ .byte 0xf0 /* 3.5" floppy */
+sectors_per_fat:
+ .word 0
+
+ /* DOSv3.4 */
+sectors_per_track:
+ .word 0
+head_count:
+ .word 0
+hidden_sector_count:
+ .long 0
+sectors_in_volume_long:
+ .long 0
+
+ /* Marmot format */
+
+ .global loaderStart
+loaderStart:
+ .word 0
+ .global loaderSectors
+loaderSectors:
+ .word 0
+ .global bootPreferredVideoMode
+bootPreferredVideoMode:
+ .word 0x0144 /* 1280x1024x32bpp */
+
+
+around: cli
+ ljmp $0, $boing
+boing: xor %ax, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ lss BOOT_SS_SP, %sp
+ sti
+
+ mov %dl, bootDevice
+ call VideoInit
+ call LoadRest
+ jmp Loader
+
+
+ /*
+ * VideoInit --
+ *
+ * Initialize the display.
+ *
+ */
+VideoInit:
+ /* 80x25 16 colors */
+ movb $0x03, %al /* ah is already zeroed */
+ int $0x10
+ /* disable cursor */
+ mov $1, %ah
+ mov $0x2000, %cx
+ int $0x10
+
+ xor %dx, %dx
+ call MoveCursor
+ ret
+
+
+ /*
+ * MoveCursor --
+ *
+ * Position the cursor to the coordinates in dx.
+ *
+ */
+
+MoveCursor:
+ mov $2, %ah
+ mov $1, %bh
+ int $0x10
+ ret
+
+
+ /*
+ * PrintMessage --
+ *
+ * Print the message pointed to by si.
+ *
+ */
+
+PrintMessage:
+ mov $0x0e, %ah
+ mov $0x0100, %bx
+1: lodsb
+ test %al, %al
+ jz 1f
+ int $0x10
+ jmp 1b
+1: ret
+
+
+ /*
+ * LoadRest --
+ *
+ * Load the rest of the boot loader from disk into memory.
+ *
+ */
+
+LoadRest:
+ call ResetDevice
+
+ /* Get driver parameters */
+ mov $8, %ah
+ mov bootDevice, %dl
+ int $0x13
+ jnc 1f
+
+ mov $noParams, %si
+ jmp Die
+
+1: /* Important values from int 13,8 are:
+ * cx[5:0] - sectors per track
+ * dh - heads
+ */
+
+ movb %dh, driveHeads
+ and $0x3f, %cx
+ movb %cl, sectorsPerTrack
+
+ mov esSave, %es
+ xor %bx, %bx
+ xor %ax, %ax
+
+ReadLoop:
+ inc %ax
+ cmpw loaderSectors, %ax
+ jbe 1f
+
+ /* All done */
+ xor %ax, %ax
+ mov %ax, %es
+ ret
+
+1: mov $3, %dx
+ mov %dx, tries
+ mov %ax, sector
+
+_retry:
+ call LBA2CHS
+
+ mov $0x0201, %ax
+ mov bootDevice, %dl
+ int $0x13
+ jnc 1f
+
+ /* read failed - reset and try again */
+ mov sector, %ax
+ decw tries
+ jnz _retry
+
+ /* oops - too many tries */
+ mov $readFailed, %si
+ jmp Die
+
+1: addw $0x20, esSave
+ mov esSave, %es
+ mov sector, %ax
+ jmp ReadLoop
+
+
+ /*
+ * LBA2CHS --
+ *
+ * Convert the block number in ax to a CHS value in cx and dh.
+ *
+ * Clobbers ax, cx, dx
+ */
+
+ .global LBA2CHS
+LBA2CHS:
+ xor %dx, %dx
+ divw sectorsPerTrack
+ mov %dx, chsScratch
+
+ xor %dx, %dx
+ divw driveHeads
+
+ /* Values are:
+ *
+ * (%sp) sector
+ * ax cylinder
+ * dx head
+ */
+
+ shl $8, %dx /* dh => head */
+ mov %ax, %cx
+ shl $8, %cx /* ch => low 8 bits of cylinder */
+ shr $2, %ax
+ and $0xc0, %al
+ movb chsScratch, %cl
+ inc %cl
+ and $0x3f, %cl /* cl[5:0] => sector */
+ or %al, %cl /* cl[7:6] => high 2 bits of cylinder */
+
+ .global LBA2CHS_Done
+LBA2CHS_Done:
+ ret
+
+
+ /*
+ * ResetDevice --
+ *
+ * Reset the disk controller for the boot device.
+ *
+ */
+
+ResetDevice:
+ mov bootDevice, %dl
+ mov $0, %ah
+ int $0x13
+ jc 1f
+ ret
+
+1: mov $resetFailed, %si
+
+ /* fall through */
+
+
+ /*
+ * Die --
+ *
+ * Print the message pointed to by %si and halt.
+ */
+
+ .global Die /* so it's visible to VProbes */
+Die: xor %dx, %dx
+ call MoveCursor
+ push %si
+ mov $diskn, %si
+ call PrintMessage
+ pop %si
+ call PrintMessage
+ mov $failed, %si
+ pushw $halt
+ jmp PrintMessage
+
+halt: hlt
+ jmp halt
+
+
+ /* %ss/%sp values for lss - saves a byte over two movs */
+BOOT_SS_SP:
+ .word BOOT_SP, BOOT_SS
+ /* %es value during load loop */
+esSave:
+ .word LOADER_START >> 4
+ /* start of string for Die */
+diskn:
+ .asciz "Disk "
+ /* end of string for Die */
+failed:
+ .asciz " failed!!!"
+ /* various strings for error messages */
+resetFailed:
+ .asciz "reset"
+readFailed:
+ .asciz "read"
+noParams:
+ .asciz "get params"
+
+
+ /* Master boot record */
+
+ .org 0x1b8
+disk_signature:
+ .long 0xbebaefbe
+ .word 0
+partitions:
+ .fill 64, 1, 0
+signature:
+ .byte 0x55, 0xaa
+
+
+ /*
+ * .boot_bss --
+ *
+ * Scratch area for the boot loader located at 0x7e00.
+ *
+ */
+
+ .section .boot_bss
+bootDevice:
+ .byte 0
+driveHeads:
+ .byte 0
+sectorsPerTrack:
+ .byte 0
+tries:
+ .byte 0
+sector:
+ .word 0
+chsScratch:
+ .word 0
diff --git a/Marmot/cpu.c b/Marmot/cpu.c
new file mode 100644
index 0000000..dfb570c
--- /dev/null
+++ b/Marmot/cpu.c
@@ -0,0 +1,64 @@
+/*
+ * cpu.c
+ *
+ * CPU-specific functionality.
+ */
+
+
+#include <marmot.h>
+
+
+struct {
+ uint64 nStandard;
+ uint64 nHypervisor;
+ uint64 nExtended;
+ struct {
+ UReg eax;
+ UReg ebx;
+ UReg ecx;
+ UReg edx;
+ } features[];
+} *CPUIDInfo;
+
+
+uint32
+CPU_GetFeature(uint32 feature)
+{
+ uint32 type, fcn, reg, bl, bh, mask, idx, features = 0;
+
+ type = (feature & CPUID_TYPE_MASK) >> CPUID_TYPE_SHIFT;
+ fcn = (feature & CPUID_FCN_MASK) >> CPUID_FCN_SHIFT;
+ reg = (feature & CPUID_REG_MASK) >> CPUID_REG_SHIFT;
+ bl = (feature & CPUID_LBIT_MASK) >> CPUID_LBIT_SHIFT;
+ bh = (feature & CPUID_HBIT_MASK) >> CPUID_HBIT_SHIFT;
+
+ mask = (~((1 << bh) - 1)) - ((1 << bl) - 1);
+
+ idx = 0;
+ if (type == CPUID_FEATURES_HYPERVISOR) {
+ if (CPUIDInfo->nHypervisor == 0) {
+ return FALSE;
+ }
+
+ idx += CPUIDInfo->nStandard;
+ } else if (type == CPUID_FEATURES_EXTENDED) {
+ idx += CPUIDInfo->nStandard + CPUIDInfo->nHypervisor;
+ }
+
+ switch (reg) {
+ case CPUID_REGISTER_EAX:
+ features = CPUIDInfo->features[idx].eax;
+ break;
+ case CPUID_REGISTER_EBX:
+ features = CPUIDInfo->features[idx].ebx;
+ break;
+ case CPUID_REGISTER_ECX:
+ features = CPUIDInfo->features[idx].ecx;
+ break;
+ case CPUID_REGISTER_EDX:
+ features = CPUIDInfo->features[idx].edx;
+ break;
+ }
+
+ return (features & mask) >> bl;
+}
diff --git a/Marmot/cpu.h b/Marmot/cpu.h
new file mode 100644
index 0000000..f6bd403
--- /dev/null
+++ b/Marmot/cpu.h
@@ -0,0 +1,186 @@
+/*
+ * cpu.h --
+ *
+ * All the various CPU defines are placed here to avoid
+ * cluttering marmot.h too much.
+ */
+
+#ifndef _CPU_H
+#define _CPU_H
+
+#include <types.h>
+
+#define APIC_BASE_MSR 0x1b
+
+
+/*
+ * Note about hypervisor features:
+ *
+ * If cpuid[1].ecx[31] is set, then a hypervisor is present and the
+ * hypervisor functions (0x400000xx) can be queried (which isn't to
+ * say a hypervisor *isn't* present if the bit isn't set).
+ *
+ * VMware defines the following leaves:
+ *
+ * 0x40000000.eax: Max cpuid input value
+ * .ebx: 0x61774d56 (awMV)
+ * .ecx: 0x4d566572 (MVer)
+ * .edx: 0x65726177 (eraw)
+ *
+ * 0x4000000a.eax: Virtual TSC frequency in kHz
+ * .ebx: Virtual bus (local APIC timer) frequency in kHz
+ * .ecx: Reserved
+ * .edx: Reserved
+ *
+ *
+ * Microsoft defines the following leaves:
+ *
+ * 0x40000000.eax: Max cpuid input value
+ * .ebx: 0x7263694d (rciM)
+ * .ecx: 0x666f736f (foso)
+ * .edx: 0x76482074 (vH t)
+ *
+ * 0x40000001.eax: 0x31237648 (1#vH)
+ * .ebx: Reserved
+ * .ecx: Reserved
+ * .edx: Reserved
+ *
+ * 0x40000002.eax: Build number
+ * .ebx: Bits 31-16: Major version
+ * Bits 15-0: Minor version
+ * .ecx: Service pack
+ * .edx: Bits 31-24: Service branch
+ * Bits 23-0: Service number
+ *
+ * 0x40000003.eax: Bit 0: VP runtime (HV_X64_MSR_VP_RUNTIME) is available.
+ * Bit 1: Partition reference counter
+ * (HV_X64_MSR_TIME_REF_COUNT) is available.
+ * Bit 2: Basic SynIC MSRs (HV_X64_MSR_SCONTROL through
+ * HV_X64_MSR_EOM and HV_X64_MSR_SINT0 through
+ * HV_X64_MSR_SINT15) are available.
+ * Bit 3: Synthetic timer MSRs (HV_X64_STIMER0_CONFIG
+ * through HV_X64_STIMER3_COUNT) are available.
+ * Bit 4: APIC access MSRs (HV_X64_MSR_EOI,
+ * HV_X64_MSR_ICR, and HV_X64_MSR_TPR) are
+ * available.
+ * Bit 5: Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and
+ * HV_X64_MSR_HYPERCALL) are available.
+ * Bit 6: Access virtual process index MSR
+ * (HV_X64_MSR_VP_INDEX) is available.
+ * Bit 7: Virtual system reset MSR (HV_X64_MSR_RESET) is
+ * available.
+ * Bits 8-31: Reserved
+ * .ebx: Flags that parent partition specified to create child
+ * partition (HV_PARTITION_PRIVILEGE_MASK):
+ * Bit 0: CreatePartitions
+ * Bit 1: AccessPartitionId
+ * Bit 2: AccessMemoryPool
+ * Bit 3: AdjustMessageBuffers
+ * Bit 4: PostMessages
+ * Bit 5: SignalEvents
+ * Bit 6: CreatePort
+ * Bit 7: ConnectPort
+ * Bit 8: AccessStats
+ * Bit 9: IteratePhysicalHardware
+ * Bit 10: DeprecatedExposeHyperthreads
+ * Bit 11: Debugging
+ * Bit 12: CpuPowerManagement
+ * Bits 13-31: Reserved
+ * .ecx: Power management information:
+ * Bits 0-3: Maximum processor power state:
+ * 0 = C0, 1 = C1, 2 = C2, 3 = C3
+ * Bits 4-31: Reserved
+ * .edx: Miscellaneous features available to partition:
+ * Bit 0: MWAIT is available.
+ * Bit 1: Guest debugging support is available.
+ * Bit 2: Performance monitor support is available.
+ * Bits 3-31: Reserved
+ *
+ * 0x40000004: Hypervisor recommendations to guest.
+ * .eax: Bit 0: Use hypercall for address space switch instead
+ * of mov to %cr3.
+ * Bit 1: Use hypercall for TLB flush instead of invlpg
+ * or mov to %cr3.
+ * Bit 2: User hypercall for remote TLB flush instead of
+ * IPI.
+ * Bit 3: Use MSRs to access APIC registers EOI, ICR, and
+ * TPR instead of memory-mapped APIC registers.
+ * Bit 4: User hypervisor MSR to initiate system RESET.
+ * Bit 5: Use "relaxed timing" in this partition.
+ * Bit 6-31: Reserved
+ * .ebx: Recommended spinlock retries before notifying
+ * hypervisor (0xffffffff indicates never retry).
+ * .ecx: Reserved
+ * .edx: Reserved
+ *
+ * 0x40000005.eax: Maximum number of virtual processors supported.
+ * .ebx: Maximum number of physical processors supported.
+ * .ecx: Reserved
+ * .edx: Reserved
+ *
+ */
+
+
+#define CPUID_FEATURES_STANDARD 0
+#define CPUID_FEATURES_HYPERVISOR 4
+#define CPUID_FEATURES_EXTENDED 8
+
+#define CPUID_REGISTER_EAX 0
+#define CPUID_REGISTER_EBX 1
+#define CPUID_REGISTER_ECX 2
+#define CPUID_REGISTER_EDX 3
+
+/*
+ * The feature mask for each feature looks like:
+ *
+ * 0000 0000 0000 tttt ffff rrll lllh hhhh
+ *
+ * Type is 0, 4, or 8 (standard, hypervisor, or extended).
+ * Function is the function number within the type.
+ * Register is eax, ebx, ecx, or edx.
+ * The feature returned extends from the low bit to the high bit.
+ */
+
+
+#define CPUID_TYPE_SHIFT 16
+#define CPUID_TYPE_MASK 0x000f0000
+#define CPUID_FCN_SHIFT 12
+#define CPUID_FCN_MASK 0x0000f000
+#define CPUID_REG_SHIFT 10
+#define CPUID_REG_MASK 0x00000c00
+#define CPUID_LBIT_SHIFT 5
+#define CPUID_LBIT_MASK 0x000003e0
+#define CPUID_HBIT_SHIFT 0
+#define CPUID_HBIT_MASK 0x0000001f
+
+#define CPUID_FEATURE(type,fcn,reg,bl,bh) (((type) << CPUID_TYPE_SHIFT) | \
+ ((fcn) << CPUID_FCN_SHIFT) | \
+ ((reg) << CPUID_REG_SHIFT) | \
+ ((bl) << CPUID_LBIT_SHIFT) | \
+ ((bh) << CPUID_HBIT_SHIFT))
+
+#define CPU_HYPERVISOR_PRESENT CPUID_FEATURE(CPUID_FEATURES_STANDARD, \
+ 1, \
+ CPUID_REGISTER_ECX, \
+ 31, \
+ 31)
+
+#define CPU_APIC_ENABLED CPUID_FEATURE(CPUID_FEATURES_STANDARD, \
+ 1, \
+ CPUID_REGISTER_EDX, \
+ 9, \
+ 9)
+
+#define CPU_VMW_VTSC_KHZ CPUID_FEATURE(CPUID_FEATURES_HYPERVISOR, \
+ 0xa, \
+ CPUID_REGISTER_EAX, \
+ 0, \
+ 31)
+
+/*
+ * Check whether the indicated feature bit is set.
+ */
+uint32 CPU_GetFeature(uint32 feature);
+
+
+#endif
diff --git a/Marmot/cs.pl b/Marmot/cs.pl
new file mode 100644
index 0000000..ac7fc9e
--- /dev/null
+++ b/Marmot/cs.pl
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+#
+# cs.pl --
+#
+# Calculate sectors and save to loaderSectors
+
+use strict;
+use warnings;
+
+my $off = 0;
+
+my $map = "link.map";
+open MAP, "<$map" or die "Unable to open $map: $!";
+while (my $line = <MAP>) {
+ if ($line =~ m/(0x[0-9a-f]+)\s+loaderSectors/) {
+ $off = hex($1) - 0x7c00;
+ last;
+ }
+}
+
+my $bytes = (stat('boot'))[7];
+my $sectors = int(($bytes + 512) / 512) - 1;
+
+my $image = "boot.img";
+
+open IMG, "+<$image" or die "Unable to open $image: $!";
+binmode IMG;
+seek IMG, $off, 0;
+
+my $n = syswrite IMG, pack('S', $sectors), 2;
+
+close IMG;
+
+print sprintf(" ==> Writing 0x%04x to loaderSectors at offset 0x%x\n",
+ $sectors, $off);
diff --git a/Marmot/cursor.xbm b/Marmot/cursor.xbm
new file mode 100644
index 0000000..b48df35
--- /dev/null
+++ b/Marmot/cursor.xbm
@@ -0,0 +1,31 @@
+/*
+ * Default cursor
+ *
+ * Looks something like:
+ *
+ * X . . . . . . . . . . . . . . .
+ * . X X . . . . . . . . . . . . .
+ * . X X X X . . . . . . . . . . .
+ * . . X . X X X . . . . . . . . .
+ * . . X X X . X X X . . . . . . .
+ * . . . X . X . X X X X . . . . .
+ * . . . X X . X . . X X X X . . .
+ * . . . . X . . X . X . . . . . .
+ * . . . . X X . . X X . . . . . .
+ * . . . . . X X X X X X . . . . .
+ * . . . . . X X . . X X X . . . .
+ * . . . . . . X . . . X X X . . .
+ * . . . . . . X . . . . X X X . .
+ * . . . . . . . . . . . . X X X .
+ * . . . . . . . . . . . . . X X .
+ * . . . . . . . . . . . . . . . .
+ */
+
+
+#define cursor_width 16
+#define cursor_height 16
+#define cursor_x_hot 0
+#define cursor_y_hot 0
+static unsigned short cursor_bits[] = {
+ 0x0001, 0x0006, 0x001e, 0x0074, 0x01dc, 0x07a8, 0x1e58, 0x0290, 0x0330,
+ 0x07e0, 0x0e60, 0x1c40, 0x3840, 0x7000, 0x6000, 0x0000 };
diff --git a/Marmot/device.c b/Marmot/device.c
new file mode 100644
index 0000000..c001310
--- /dev/null
+++ b/Marmot/device.c
@@ -0,0 +1,19 @@
+/*
+ * device.c
+ *
+ * Device registration and management.
+ */
+
+
+
+Device
+Device_Register(DeviceInfo info)
+{
+
+}
+
+void
+Device_Unregister(Device d)
+{
+
+}
diff --git a/Marmot/dumpRegs.vp b/Marmot/dumpRegs.vp
new file mode 100644
index 0000000..c09afe5
--- /dev/null
+++ b/Marmot/dumpRegs.vp
@@ -0,0 +1,476 @@
+; Dump registers
+
+(defun rev (n)
+ (| (& 0x00000000000000ff (>> n 56))
+ (& 0x000000000000ff00 (>> n 40))
+ (& 0x0000000000ff0000 (>> n 24))
+ (& 0x00000000ff000000 (>> n 8))
+ (& 0x000000ff00000000 (<< n 8))
+ (& 0x0000ff0000000000 (<< n 24))
+ (& 0x00ff000000000000 (<< n 40))
+ (& 0xff00000000000000 (<< n 56))))
+
+(defun dump-regs ()
+ (printf "AX %016x BX %016x CX %016x DX %016x\n"
+ RAX RBX RCX RDX)
+ (printf "SI %016x DI %016x BP %016x SP %016x\n"
+ RSI RDI RBP RSP)
+ (printf "R8 %016x R9 %016x R0 %016x R1 %016x\n"
+ R8 R9 R10 R11)
+ (printf "R2 %016x R3 %016x R4 %016x R5 %016x\n"
+ R12 R13 R14 R15)
+ (printf "IP %016x FLAGS %016x\n"
+ RIP EFLAGS)
+ (printf "CS %04x DS %04x ES %04x FS %04x GS %04x SS %04x\n"
+ CS DS ES FS GS SS)
+ (printf "CR0 %016x CR2 %016x CR3 %016x\n"
+ CR0 CR2 CR3)
+ (printf "CR4 %016x CR8 %016x EFER %016x\n\n"
+ CR4 CR8 EFER))
+
+
+(vprobe GUEST:_start
+ (printf "\n======================================================\n"))
+
+(vprobe GUEST:Loader
+ (printf "In the loader (%s)! (%016x)\n"
+ PROBENAME (getguest 0x8000))
+ (dump-regs))
+
+;(definteger vesa-addr)
+;(defstring vesa-str)
+
+; careful - esx4x requires 3-4 args, but ws65 requires 2-3 for get*str.
+;(defun set-vesa-str ()
+; (getgueststr vesa-str (| (>> (& vesa-addr 0xffff0000) 12)
+; (getgueststr vesa-str 255 (| (>> (& vesa-addr 0xffff0000) 12)
+; (& vesa-addr 0xffff))))
+
+;(defun vesa-modes (max off)
+; (cond ((> max 0)
+; (do (setint vesa-addr (& 0xffff (getguest "VideoModeList" off)))
+; (printf " 0x%04x (%d)\n" vesa-addr vesa-addr)
+; (vesa-modes (- max 1) (+ off 2))))))
+
+;(defun dump-vesa ()
+; (printf "VbeSignature: 0x%08x\n"
+; (& 0xffffffff (getguest "VbeSignature")))
+; (printf "VbeVersion: 0x%04x\n"
+; (& 0xffff (getguest "VbeVersion")))
+; (setint vesa-addr (& 0xffffffff (getguest "OemStringPtr")))
+; (set-vesa-str)
+; (printf "OemStringPtr: 0x%08x (%s)\n"
+; vesa-addr vesa-str)
+; (printf "Capabilities: 0x%08x\n"
+; (& 0xffffffff (getguest "Capabilities")))
+; (printf "VideoModePtr: 0x%08x\n"
+; (& 0xffffffff (getguest "VideoModePtr")))
+; (setint vesa-addr (& 0xffff (getguest "TotalMemory")))
+; (printf "TotalMemory: 0x%04x (%dkB)\n"
+; vesa-addr (* 64 vesa-addr))
+; (printf "OemSoftwareRev: 0x%04x\n"
+; (& 0xffff (getguest "OemSoftwareRev")))
+; (setint vesa-addr (& 0xffffffff (getguest "OemVendorNamePtr")))
+; (set-vesa-str)
+; (printf "OemVendorNamePtr 0x%08x (%s)\n"
+; vesa-addr vesa-str)
+; (setint vesa-addr (& 0xffffffff (getguest "OemProductNamePtr")))
+; (set-vesa-str)
+; (printf "OemProductNamePtr: 0x%08x (%s)\n"
+; vesa-addr vesa-str)
+; (setint vesa-addr (& 0xffffffff (getguest "OemProductRevPtr")))
+; (set-vesa-str)
+; (printf "OemProductRevPtr: 0x%08x (%s)\n\n"
+; vesa-addr vesa-str))
+
+
+;(defun dump-mode-info (o)
+; (cond ((< o 48)
+; (do (printf " %3d: %016x %016x\n"
+; o
+; (rev (getguest "VESAModeInfo" o))
+; (rev (getguest "VESAModeInfo" (+ o 8))))
+; (dump-mode-info (+ o 16))))))
+
+;(defun dump-edid-info (o)
+; (cond ((< o 256)
+; (do (printf " %3d: %016x %016x\n"
+; o
+; (rev (getguest "EDIDBlock" o))
+; (rev (getguest "EDIDBlock" (+ o 8))))
+; (dump-edid-info (+ o 16))))))
+
+
+;(vprobe GUEST:HaveVESA
+; (printf "VESA Info:\n")
+; (dump-vesa)
+; (dump-mode-info 0)
+; (dump-edid-info 0)
+; (dump-regs))
+
+;(definteger vesa-scratch)
+;(vprobe GUEST:vesa
+; (printf "vesa (%s)\n" PROBENAME)
+; (setint vesa-scratch (getguest "VideoModeList"))
+; (printf " VideoModeList:\n %016x" (rev vesa-scratch))
+; (setint vesa-scratch (getguest "VideoModeList" 8))
+; (printf " %016x\n" (rev vesa-scratch))
+; (printf " VESAModeInfo:\n")
+; (dump-regs))
+;
+;(definteger mp-scratch)
+;(vprobe GUEST:HaveMPConfig
+; (printf "HaveMPConfig\n")
+; (setint mp-scratch (& 0xffffffff (getguest "MPFloatingPointer")))
+; (printf " %016x\n" (rev (getguest mp-scratch)))
+; (printf " %016x\n" (rev (getguest (+ mp-scratch 8))))
+; (dump-regs));
+
+(defun conv (m)
+ (cond ((< m 1024)
+ (printf "(%dB)" m))
+ ((< m 1048576)
+ (printf "(%dkiB)" (/ m 1024)))
+ (1
+ (printf "(%dMiB)" (/ m 1048576)))))
+
+
+(defun mem-type (t)
+ (cond ((== t 1)
+ "(RAM) ")
+ ((== t 2)
+ "(RSVD) ")
+ ((== t 3)
+ "(ACPI data)")
+ ((== t 4)
+ "(ACPI NVS) ")
+ (1
+ "(????) ")))
+
+(definteger smap-base)
+(definteger smap-length)
+(definteger smap-type)
+
+(defun e820-entry (n)
+ (setint smap-base (getguest "e820_map" (* n 20)))
+ (setint smap-length (getguest "e820_map" (+ (* n 20) 8)))
+ (setint smap-type (& (getguest "e820_map" (+ (* n 20) 16)) 0xffffffff))
+
+ (printf "E820 %2d: 0x%016x - 0x%016x %s - "
+ n smap-base (+ smap-base smap-length)
+ (mem-type smap-type))
+ (conv smap-length)
+ (printf "\n")
+ (cond ((< n (getguest "e820_entries"))
+ (e820-entry (+ n 1)))))
+
+(defun e820-map ()
+ (e820-entry 0)
+ (printf "\n"))
+
+(defun dump-gdt ()
+ (printf "GDT:\n")
+ (printf " %016x\n" (getguest 0x1f00))
+ (printf " %016x\n" (getguest 0x1f08))
+ (printf " %016x\n" (getguest 0x1f10))
+ (printf " %016x\n" (getguest 0x1f18))
+ (printf " %016x\n" (getguest 0x1f20))
+ (printf " %016x\n" (getguest 0x1f28)))
+
+
+(vprobe GUEST:RealModeFlamingDeath
+ (printf "Real mode flaming death\n")
+ (dump-regs))
+
+(vprobe GUEST:Die
+ (printf "Boot sector called die!!!!\n")
+ (dump-regs))
+
+;(vprobe GUEST:DisplayKeycode
+; (printf "DisplayKeycode (%s)\n keys %016x\n keyp %016x\n"
+; PROBENAME (rev (getguest "keys")) (getguest "keyp")))
+;(vprobe GUEST:UpdateClock
+; (printf "UpdateClock (%s)\n" PROBENAME)
+; (printf " ==> TOD: %016x\n" (rev (getguest "tod")))
+; (dump-regs))
+
+
+;(vprobe GUEST:PrintMessage
+; (printf "PrintMessage\n")
+; (printf "PrintMessage\n 0x%016x\n 0x%016x\n 0x%016x\n 0x%016x\n"
+; (getguest (+ RSP 24))
+; (getguest (+ RSP 16))
+; (getguest (+ RSP 8))
+; (getguest RSP))
+; (printf " frameBuffer: %016x\n frameBufferSize: %016x\n"
+; (getguest "frameBuffer") (getguest "frameBufferSize"))
+; (dump-regs))
+
+(vprobe GUEST:here
+ (printf "Made it here (%s)\n" PROBENAME)
+ (dump-regs)
+ (e820-map))
+
+(vprobe GUEST:IntoProtectedMode
+ (printf "IntoProtectedMode (%s)\n" PROBENAME)
+ (e820-map)
+ (dump-gdt)
+ (dump-regs))
+
+(vprobe GUEST:IntoLongMode
+ (printf "IntoLongMode (%s)\n" PROBENAME)
+ (dump-gdt)
+ (dump-regs))
+
+
+(vprobe GUEST:mapped
+ (printf "mapped (%s)\n" PROBENAME)
+ (e820-map))
+
+(definteger pciAddress)
+(definteger pciData)
+(vprobe GUEST:HavePCI
+ (setint pciAddress (getguest "pciAddress"))
+ (setint pciData (getguest "pciData"))
+ (printf "PCI: %02x:%02x.%1x %04x:%04x\n"
+ (& (>> pciAddress 16) 0xff) (& (>> pciAddress 11) 0x1f)
+ (& (>> pciAddress 8) 0x7)
+ (& pciData 0xffff) (& (>> pciData 16) 0xffff)))
+
+
+(definteger tmp)
+(defun dump-irq-routing-table (t o l)
+ (cond ((< o l)
+ (do (setint tmp (getguest (+ t o)))
+ (printf " %016x\n" tmp)
+ (dump-irq-routing-table t (+ o 16) l)))))
+
+(definteger table)
+(definteger tb)
+(vprobe GUEST:RouteIRQ
+ (setint table (getguest "routingTable"))
+ (setint tb (>> (getguest table) 48))
+ (printf "IRQ Routing (table at %x):\n" table)
+ (cond ((> table 0)
+ (dump-irq-routing-table table 0 tb))))
+
+
+;(vprobe GUEST:VideoInit (printf "VideoInit: (%s)\n" PROBENAME)(dump-regs))
+;(vprobe GUEST:MapIORegion (printf "MapIORegion: (%s)\n" PROBENAME)(dump-regs))
+
+
+
+
+(vprobe GUEST:test
+ (printf "test (%s)!\n tval = 0x%016x\n tval2 = 0x%016x\n"
+ PROBENAME (getguest "tval") (getguest "tval2")))
+
+
+
+; (printf " bitmap[0]: %016x\n bitmap[8]: %016x\n"
+; (rev (getguest 0x18000))(rev (getguest 0x18008)))
+; (dump-regs))
+
+(definteger pts)
+(defun dump-pt (addr)
+ (printf "Walking page tables for faulting address %016x\n" addr)
+ (setint pts (getguest (+ (& CR3 0xfffffffffffff000)
+ (* 8 (& (>> addr 39) 0x1ff)))))
+ (printf " => PML4E: %016x\n" pts)
+ (setint pts (getguest (+ (& pts 0x000ffffffffff000)
+ (* 8 (& (>> addr 30) 0x1ff)))))
+ (printf " => PDPE: %016x\n" pts)
+ (setint pts (getguest (+ (& pts 0x000ffffffffff000)
+ (* 8 (& (>> addr 21) 0x1ff)))))
+ (printf " => PDE: %016x\n" pts)
+ (setint pts (getguest (+ (& pts 0x000ffffffffff000)
+ (* 8 (& (>> addr 12) 0x1ff)))))
+ (printf " => PTE: %016x\n" pts))
+
+;(defun print-idt (v)
+; (printf " %3d: 0x%016x%016x\n"
+; v
+; (getguest (+ 0x1008 (* v 16)))
+; (getguest (+ 0x1000 (* v 16))))
+; (cond ((> v 0)
+; (print-idt (- v 1)))))
+;(vprobe GUEST:IDTDone
+; (printf "IDTDone (%s)\n" PROBENAME)
+; (print-idt 48)
+; (dump-regs))
+
+;(defun ptes (n)
+; (printf " PTE %x: 0x%016x\n"
+; n (getguest (+ 0x5000 (* 8 n))))
+; (cond ((> n 0)
+; (ptes (- n 1)))))
+
+;(vprobe GUEST:PageDone
+; (printf "PageDone (%s)\n (limit: %08x)\n"
+; PROBENAME (& 0xffffffff (getguest "e820_map" 8)))
+; (printf " PML4E: 0x%016x\n PDPTE: 0x%016x\n PDE: 0x%016x\n"
+; (getguest 0x2000)
+; (getguest 0x3000)
+; (getguest 0x4000))
+; (ptes 10))
+
+
+;(vprobe GUEST:foo
+; (printf "foo (%s): 0x%08x:0x%08x\n" PROBENAME
+; (& 0xffffffff (getguest RSP))
+; (& 0xffffffff (getguest (+ RSP 4))))
+; (printf "GDT: 00: %016x\n 08: %016x\n 10: %016x\n 18: %016x\n"
+; (getguest 0x1f00)
+; (getguest 0x1f08)
+; (getguest 0x1f10)
+; (getguest 0x1f18))
+; (dump-regs))
+
+;(vprobe GUEST_WRITE:0x1f10
+; (printf "GUEST_WRITE:0x1f10: %s\n" PROBENAME)
+; (dump-regs))
+
+
+;(defun dump-tss (off)
+; (printf " TSS+%2x: %016x\n" off (getguest "tss_start" off))
+; (cond (off
+; (dump-tss (- off 8)))))
+
+;(vprobe GUEST:EndPopTSS
+; (printf "EndPopTSS (%s), TSS:\n" PROBENAME)
+; (dump-tss 96)
+; (dump-gdt)
+; (dump-regs))
+
+;(vprobe GUEST:PopulateTSS
+; (printf "PopulateTSS: (%s)\nPhysmem bitmask:\n" PROBENAME)
+; (printf " %016x\n" (rev (getguest
+
+;(defun dump-cpuid-fun (current max struct)
+; (printf " %02x: %08x %08x %08x %08x\n" current
+; (& 0xffffffff (getguest struct))
+; (& 0xffffffff (getguest (+ struct 4)))
+; (& 0xffffffff (getguest (+ struct 8)))
+; (& 0xffffffff (getguest (+ struct 12))))
+; (cond ((< current (- max 1))
+; (dump-cpuid-fun (+ current 1) max (+ struct 16)))))
+
+;(definteger cpuid-struct)
+;(definteger cpuid-max)
+;(definteger cpuid-base)
+;(defun dump-cpuid ()
+; (setint cpuid-struct (getguest "CPUIDInfo"))
+
+ ; Level 0
+; (setint cpuid-max (getguest cpuid-struct))
+; (setint cpuid-base (+ cpuid-struct 24))
+
+; (printf " CPUID Info for functions 0 (entries %x)\n" cpuid-max)
+; (cond ((> cpuid-max 0)
+; (dump-cpuid-fun 0 cpuid-max cpuid-base)))
+ ; skip to next level
+; (setint cpuid-base (+ cpuid-base (* cpuid-max 16)))
+
+ ; Level 4
+; (setint cpuid-max (getguest (+ cpuid-struct 8)))
+; (cond ((> cpuid-max 0)
+; (do (printf " CPUID Info for functions 4 (entries %x)\n"
+; cpuid-max)
+; (dump-cpuid-fun 0 cpuid-max cpuid-base))))
+ ; skip to next level
+; (setint cpuid-base (+ cpuid-base (* cpuid-max 16)))
+
+ ; Level 8
+; (setint cpuid-max (getguest (+ cpuid-struct 16)))
+; (printf " CPUID Info for functions 8 (entries %x)\n" cpuid-max)
+; (cond ((> cpuid-max 0)
+; (dump-cpuid-fun 0 cpuid-max cpuid-base))))
+
+;(vprobe GUEST:CPUFeaturesDone
+; (printf "CPUFeaturesDone (%s)\n" PROBENAME)
+; (dump-cpuid))
+
+(defun dump-stack (off)
+ (printf " %4x(%%rsp): %016x\n" off (getguest (+ RSP off)))
+ (cond (off
+ (dump-stack (- off 8)))))
+
+(vprobe GUEST:Fatal64
+ (printf "Fatal64!\n")
+ (dump-stack 64)
+ (cond (CR2 (dump-pt CR2)))
+ (dump-regs))
+
+(defstring stk)
+(defun badness (a)
+ (printf "Badness (%s): code = 0x%08x!\n faulting insn = %016x\n %s\n"
+ PROBENAME a (rev (getguest RIP)) stk)
+ (dump-stack 64)
+ (dump-gdt)
+ (dump-regs))
+
+(vprobe GUEST:HandlePF
+ (printf "HandlePF (%s)\n" PROBENAME)
+ (dump-stack 64)
+ (cond (CR2 (dump-pt CR2)))
+ (dump-regs))
+
+(vprobe Guest_UD (badness ARG0))
+(vprobe Guest_TS (badness ARG0))
+(vprobe Guest_DF (badness ARG0))
+(vprobe Guest_SS (badness ARG0))
+(vprobe Guest_GP (badness ARG0))
+(vprobe Guest_PF (badness ARG0))
+(vprobe Guest_TripleFault (badness 0))
+
+;(defaggr mouse 1 0)
+;(vprobe Guest_IRQ
+; (cond ((== ARG0 0x2c)
+; (aggr mouse (1) () 1))))
+;(vprobe VMM1Hz
+; (printf "\n")
+; (logaggr mouse)
+; (clearaggr mouse))
+
+;(vprobe Guest_IRQ
+; (cond ((!= ARG0 0x20)
+; (do (printf "%s: tick (0x%x)\n" PROBENAME ARG0)
+; (dump-regs)))))
+
+;(defaggr rip 1 0)
+;(vprobe USEC:1001
+; (aggr rip (RIP) () 1))
+;(vprobe VMM1Hz
+; (logaggr rip)
+; (clearaggr rip))
+
+;(vprobe GUEST:LBA2CHS (printf "%s:\n" PROBENAME)(dump-regs))
+;(vprobe GUEST:LBA2CHS_Done (printf "%s:\n" PROBENAME)(dump-regs))
+
+
+;(definteger dbt-addr)
+;(definteger dbt)
+
+;(defun byte (i b)
+; (& 0xff (>> i b)))
+
+;(defun dump-dbt ()
+; (setint dbt-addr (| (& 0xfffff (<< ES 4)) (& 0xffff RDI)))
+; (setint dbt (getguest dbt-addr))
+; (printf "Disk Base Table (0x%08x)\n" dbt-addr)
+; (printf "00: %02x\n" (byte dbt 0))
+; (printf "01: %02x\n" (byte dbt 1))
+; (printf "02: %02x\n" (byte dbt 2))
+; (printf "03: %02x\n" (byte dbt 3))
+; (printf "04: %02x\n" (byte dbt 4))
+; (printf "05: %02x\n" (byte dbt 5))
+; (printf "06: %02x\n" (byte dbt 6))
+; (printf "07: %02x\n" (byte dbt 7))
+; (setint dbt (getguest (+ dbt-addr 8)))
+; (printf "08: %02x\n" (byte dbt 0))
+; (printf "09: %02x\n" (byte dbt 1))
+; (printf "0a: %02x\n" (byte dbt 2)))
+
+;(vprobe GUEST:_HaveParams
+; (dump-dbt)
+; (dump-regs))
diff --git a/Marmot/font.S b/Marmot/font.S
new file mode 100644
index 0000000..2b078e0
--- /dev/null
+++ b/Marmot/font.S
@@ -0,0 +1,776 @@
+ .section .data
+ .align 8
+ .global fontTable
+fontTable:
+ .long G0000
+ .word 16, 16
+ .long G0001
+ .word 16, 16
+ .long G0002
+ .word 16, 16
+ .long G0003
+ .word 16, 16
+ .long G0004
+ .word 16, 16
+ .long G0005
+ .word 16, 16
+ .long G0006
+ .word 16, 16
+ .long G0007
+ .word 16, 16
+ .long G0008
+ .word 16, 16
+ .long G0009
+ .word 16, 16
+ .long G000A
+ .word 16, 16
+ .long G000B
+ .word 16, 16
+ .long G000C
+ .word 16, 16
+ .long G000D
+ .word 16, 16
+ .long G000E
+ .word 16, 16
+ .long G000F
+ .word 16, 16
+ .long G0010
+ .word 16, 16
+ .long G0011
+ .word 16, 16
+ .long G0012
+ .word 16, 16
+ .long G0013
+ .word 16, 16
+ .long G0014
+ .word 16, 16
+ .long G0015
+ .word 16, 16
+ .long G0016
+ .word 16, 16
+ .long G0017
+ .word 16, 16
+ .long G0018
+ .word 16, 16
+ .long G0019
+ .word 16, 16
+ .long G001A
+ .word 16, 16
+ .long G001B
+ .word 16, 16
+ .long G001C
+ .word 16, 16
+ .long G001D
+ .word 16, 16
+ .long G001E
+ .word 16, 16
+ .long G001F
+ .word 16, 16
+ .long G0020
+ .word 8, 16
+ .long G0021
+ .word 8, 16
+ .long G0022
+ .word 8, 16
+ .long G0023
+ .word 8, 16
+ .long G0024
+ .word 8, 16
+ .long G0025
+ .word 8, 16
+ .long G0026
+ .word 8, 16
+ .long G0027
+ .word 8, 16
+ .long G0028
+ .word 8, 16
+ .long G0029
+ .word 8, 16
+ .long G002A
+ .word 8, 16
+ .long G002B
+ .word 8, 16
+ .long G002C
+ .word 8, 16
+ .long G002D
+ .word 8, 16
+ .long G002E
+ .word 8, 16
+ .long G002F
+ .word 8, 16
+ .long G0030
+ .word 8, 16
+ .long G0031
+ .word 8, 16
+ .long G0032
+ .word 8, 16
+ .long G0033
+ .word 8, 16
+ .long G0034
+ .word 8, 16
+ .long G0035
+ .word 8, 16
+ .long G0036
+ .word 8, 16
+ .long G0037
+ .word 8, 16
+ .long G0038
+ .word 8, 16
+ .long G0039
+ .word 8, 16
+ .long G003A
+ .word 8, 16
+ .long G003B
+ .word 8, 16
+ .long G003C
+ .word 8, 16
+ .long G003D
+ .word 8, 16
+ .long G003E
+ .word 8, 16
+ .long G003F
+ .word 8, 16
+ .long G0040
+ .word 8, 16
+ .long G0041
+ .word 8, 16
+ .long G0042
+ .word 8, 16
+ .long G0043
+ .word 8, 16
+ .long G0044
+ .word 8, 16
+ .long G0045
+ .word 8, 16
+ .long G0046
+ .word 8, 16
+ .long G0047
+ .word 8, 16
+ .long G0048
+ .word 8, 16
+ .long G0049
+ .word 8, 16
+ .long G004A
+ .word 8, 16
+ .long G004B
+ .word 8, 16
+ .long G004C
+ .word 8, 16
+ .long G004D
+ .word 8, 16
+ .long G004E
+ .word 8, 16
+ .long G004F
+ .word 8, 16
+ .long G0050
+ .word 8, 16
+ .long G0051
+ .word 8, 16
+ .long G0052
+ .word 8, 16
+ .long G0053
+ .word 8, 16
+ .long G0054
+ .word 8, 16
+ .long G0055
+ .word 8, 16
+ .long G0056
+ .word 8, 16
+ .long G0057
+ .word 8, 16
+ .long G0058
+ .word 8, 16
+ .long G0059
+ .word 8, 16
+ .long G005A
+ .word 8, 16
+ .long G005B
+ .word 8, 16
+ .long G005C
+ .word 8, 16
+ .long G005D
+ .word 8, 16
+ .long G005E
+ .word 8, 16
+ .long G005F
+ .word 8, 16
+ .long G0060
+ .word 8, 16
+ .long G0061
+ .word 8, 16
+ .long G0062
+ .word 8, 16
+ .long G0063
+ .word 8, 16
+ .long G0064
+ .word 8, 16
+ .long G0065
+ .word 8, 16
+ .long G0066
+ .word 8, 16
+ .long G0067
+ .word 8, 16
+ .long G0068
+ .word 8, 16
+ .long G0069
+ .word 8, 16
+ .long G006A
+ .word 8, 16
+ .long G006B
+ .word 8, 16
+ .long G006C
+ .word 8, 16
+ .long G006D
+ .word 8, 16
+ .long G006E
+ .word 8, 16
+ .long G006F
+ .word 8, 16
+ .long G0070
+ .word 8, 16
+ .long G0071
+ .word 8, 16
+ .long G0072
+ .word 8, 16
+ .long G0073
+ .word 8, 16
+ .long G0074
+ .word 8, 16
+ .long G0075
+ .word 8, 16
+ .long G0076
+ .word 8, 16
+ .long G0077
+ .word 8, 16
+ .long G0078
+ .word 8, 16
+ .long G0079
+ .word 8, 16
+ .long G007A
+ .word 8, 16
+ .long G007B
+ .word 8, 16
+ .long G007C
+ .word 8, 16
+ .long G007D
+ .word 8, 16
+ .long G007E
+ .word 8, 16
+ .long G007F
+ .word 16, 16
+ .long G0080
+ .word 16, 16
+ .long G0081
+ .word 16, 16
+ .long G0082
+ .word 16, 16
+ .long G0083
+ .word 16, 16
+ .long G0084
+ .word 16, 16
+ .long G0085
+ .word 16, 16
+ .long G0086
+ .word 16, 16
+ .long G0087
+ .word 16, 16
+ .long G0088
+ .word 16, 16
+ .long G0089
+ .word 16, 16
+ .long G008A
+ .word 16, 16
+ .long G008B
+ .word 16, 16
+ .long G008C
+ .word 16, 16
+ .long G008D
+ .word 16, 16
+ .long G008E
+ .word 16, 16
+ .long G008F
+ .word 16, 16
+ .long G0090
+ .word 16, 16
+ .long G0091
+ .word 16, 16
+ .long G0092
+ .word 16, 16
+ .long G0093
+ .word 16, 16
+ .long G0094
+ .word 16, 16
+ .long G0095
+ .word 16, 16
+ .long G0096
+ .word 16, 16
+ .long G0097
+ .word 16, 16
+ .long G0098
+ .word 16, 16
+ .long G0099
+ .word 16, 16
+ .long G009A
+ .word 16, 16
+ .long G009B
+ .word 16, 16
+ .long G009C
+ .word 16, 16
+ .long G009D
+ .word 16, 16
+ .long G009E
+ .word 16, 16
+ .long G009F
+ .word 16, 16
+ .long G00A0
+ .word 8, 16
+ .long G00A1
+ .word 8, 16
+ .long G00A2
+ .word 8, 16
+ .long G00A3
+ .word 8, 16
+ .long G00A4
+ .word 8, 16
+ .long G00A5
+ .word 8, 16
+ .long G00A6
+ .word 8, 16
+ .long G00A7
+ .word 8, 16
+ .long G00A8
+ .word 8, 16
+ .long G00A9
+ .word 8, 16
+ .long G00AA
+ .word 8, 16
+ .long G00AB
+ .word 8, 16
+ .long G00AC
+ .word 8, 16
+ .long G00AD
+ .word 8, 16
+ .long G00AE
+ .word 8, 16
+ .long G00AF
+ .word 8, 16
+ .long G00B0
+ .word 8, 16
+ .long G00B1
+ .word 8, 16
+ .long G00B2
+ .word 8, 16
+ .long G00B3
+ .word 8, 16
+ .long G00B4
+ .word 8, 16
+ .long G00B5
+ .word 8, 16
+ .long G00B6
+ .word 8, 16
+ .long G00B7
+ .word 8, 16
+ .long G00B8
+ .word 8, 16
+ .long G00B9
+ .word 8, 16
+ .long G00BA
+ .word 8, 16
+ .long G00BB
+ .word 8, 16
+ .long G00BC
+ .word 8, 16
+ .long G00BD
+ .word 8, 16
+ .long G00BE
+ .word 8, 16
+ .long G00BF
+ .word 8, 16
+ .long G00C0
+ .word 8, 16
+ .long G00C1
+ .word 8, 16
+ .long G00C2
+ .word 8, 16
+ .long G00C3
+ .word 8, 16
+ .long G00C4
+ .word 8, 16
+ .long G00C5
+ .word 8, 16
+ .long G00C6
+ .word 8, 16
+ .long G00C7
+ .word 8, 16
+ .long G00C8
+ .word 8, 16
+ .long G00C9
+ .word 8, 16
+ .long G00CA
+ .word 8, 16
+ .long G00CB
+ .word 8, 16
+ .long G00CC
+ .word 8, 16
+ .long G00CD
+ .word 8, 16
+ .long G00CE
+ .word 8, 16
+ .long G00CF
+ .word 8, 16
+ .long G00D0
+ .word 8, 16
+ .long G00D1
+ .word 8, 16
+ .long G00D2
+ .word 8, 16
+ .long G00D3
+ .word 8, 16
+ .long G00D4
+ .word 8, 16
+ .long G00D5
+ .word 8, 16
+ .long G00D6
+ .word 8, 16
+ .long G00D7
+ .word 8, 16
+ .long G00D8
+ .word 8, 16
+ .long G00D9
+ .word 8, 16
+ .long G00DA
+ .word 8, 16
+ .long G00DB
+ .word 8, 16
+ .long G00DC
+ .word 8, 16
+ .long G00DD
+ .word 8, 16
+ .long G00DE
+ .word 8, 16
+ .long G00DF
+ .word 8, 16
+ .long G00E0
+ .word 8, 16
+ .long G00E1
+ .word 8, 16
+ .long G00E2
+ .word 8, 16
+ .long G00E3
+ .word 8, 16
+ .long G00E4
+ .word 8, 16
+ .long G00E5
+ .word 8, 16
+ .long G00E6
+ .word 8, 16
+ .long G00E7
+ .word 8, 16
+ .long G00E8
+ .word 8, 16
+ .long G00E9
+ .word 8, 16
+ .long G00EA
+ .word 8, 16
+ .long G00EB
+ .word 8, 16
+ .long G00EC
+ .word 8, 16
+ .long G00ED
+ .word 8, 16
+ .long G00EE
+ .word 8, 16
+ .long G00EF
+ .word 8, 16
+ .long G00F0
+ .word 8, 16
+ .long G00F1
+ .word 8, 16
+ .long G00F2
+ .word 8, 16
+ .long G00F3
+ .word 8, 16
+ .long G00F4
+ .word 8, 16
+ .long G00F5
+ .word 8, 16
+ .long G00F6
+ .word 8, 16
+ .long G00F7
+ .word 8, 16
+ .long G00F8
+ .word 8, 16
+ .long G00F9
+ .word 8, 16
+ .long G00FA
+ .word 8, 16
+ .long G00FB
+ .word 8, 16
+ .long G00FC
+ .word 8, 16
+ .long G00FD
+ .word 8, 16
+ .long G00FE
+ .word 8, 16
+ .long G00FF
+ .word 8, 16
+
+
+ .align 4
+G0000: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x4A,0x51,0xEA,0x50,0x5A,0x51,0xC9,0x9E,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0001: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0x93,0xC2,0x52,0x32,0x5F,0x8A,0x52,0x71,0x93,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0002: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3B,0xA5,0xC1,0x24,0x31,0x19,0x89,0x24,0x71,0x25,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0003: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x7B,0xA5,0xC1,0x24,0x79,0x19,0xC1,0x24,0x79,0x25,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0004: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x79,0xBF,0xC2,0x48,0x7A,0x49,0xC2,0x48,0x79,0x89,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0005: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x7A,0x4D,0xC2,0x52,0x7B,0x53,0xC2,0xD6,0x7A,0x4F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0006: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x31,0xA5,0xCA,0x28,0x7A,0x31,0xCA,0x28,0x49,0xA5,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0007: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x73,0xD1,0xCA,0x10,0x73,0xD1,0xCA,0x10,0x73,0xDF,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0008: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x78,0xE1,0xC5,0x00,0x78,0xC1,0xC4,0x20,0x79,0xC1,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0009: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x45,0xF1,0xC4,0x40,0x7C,0x41,0xC4,0x40,0x44,0x41,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G000A: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x41,0xF1,0xC1,0x00,0x41,0xF1,0xC1,0x00,0x7D,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G000B: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x45,0xF1,0xC4,0x40,0x44,0x41,0xA8,0x40,0x10,0x41,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G000C: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x7D,0xF1,0xC1,0x00,0x7D,0xF1,0xC1,0x00,0x41,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G000D: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3D,0xE1,0xC1,0x10,0x41,0xE1,0xC1,0x20,0x3D,0x11,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G000E: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3C,0xE1,0xC1,0x10,0x39,0x11,0x85,0x10,0x78,0xE1,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G000F: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3D,0xF1,0xC0,0x40,0x38,0x41,0x84,0x40,0x79,0xF1,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0010: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x72,0x39,0xCA,0x20,0x4A,0x39,0xCA,0x20,0x73,0xB9,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0011: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0x89,0xCA,0x18,0x4A,0x09,0xCA,0x08,0x71,0x9D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0012: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0x99,0xCA,0x04,0x4A,0x09,0xCA,0x10,0x71,0x9D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0013: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0x99,0xCA,0x04,0x4A,0x19,0xCA,0x04,0x71,0x99,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0014: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0x85,0xCA,0x0C,0x4A,0x15,0xCA,0x1C,0x71,0x85,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0015: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x49,0x93,0xEA,0x54,0x6A,0x59,0xDB,0xD4,0x4A,0x53,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0016: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x34,0x53,0xC2,0x9A,0x31,0x17,0x89,0x12,0x71,0x13,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0017: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x7B,0xB9,0xC1,0x24,0x79,0x39,0xC1,0x24,0x79,0x39,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0018: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x33,0x25,0xC4,0xB4,0x47,0xAD,0xC4,0xA4,0x34,0xA5,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0019: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x7D,0x11,0xC1,0xB0,0x7D,0x51,0xC1,0x10,0x7D,0x11,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G001A: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3A,0x5D,0xC2,0x52,0x32,0x5D,0x8A,0x52,0x71,0x9D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G001B: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x79,0xCF,0xC2,0x10,0x79,0x91,0xC0,0x50,0x7B,0x8F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G001C: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x79,0xC1,0xC2,0x00,0x79,0x81,0xC0,0x40,0x43,0x81,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G001D: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xC1,0xC2,0x00,0x59,0x81,0xC8,0x40,0x3B,0x81,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G001E: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0xC1,0xCA,0x00,0x71,0x81,0xD0,0x40,0x4B,0x81,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G001F: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x49,0xC1,0xCA,0x00,0x49,0x81,0xC8,0x40,0x33,0x81,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0020: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G0021: .byte 0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x08,0x00,0x00
+G0022: .byte 0x00,0x00,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G0023: .byte 0x00,0x00,0x00,0x00,0x12,0x12,0x12,0x7E,0x24,0x24,0x7E,0x48,0x48,0x48,0x00,0x00
+G0024: .byte 0x00,0x00,0x00,0x00,0x08,0x3E,0x49,0x48,0x38,0x0E,0x09,0x49,0x3E,0x08,0x00,0x00
+G0025: .byte 0x00,0x00,0x00,0x00,0x31,0x4A,0x4A,0x34,0x08,0x08,0x16,0x29,0x29,0x46,0x00,0x00
+G0026: .byte 0x00,0x00,0x00,0x00,0x1C,0x22,0x22,0x22,0x1C,0x39,0x45,0x42,0x46,0x39,0x00,0x00
+G0027: .byte 0x00,0x00,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G0028: .byte 0x00,0x00,0x00,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x00
+G0029: .byte 0x00,0x00,0x00,0x20,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x10,0x10,0x20,0x00
+G002A: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x49,0x2A,0x1C,0x2A,0x49,0x08,0x00,0x00,0x00
+G002B: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x7F,0x08,0x08,0x08,0x00,0x00,0x00
+G002C: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x08,0x08,0x10
+G002D: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00
+G002E: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00
+G002F: .byte 0x00,0x00,0x00,0x00,0x02,0x02,0x04,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x00,0x00
+G0030: .byte 0x00,0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00
+G0031: .byte 0x00,0x00,0x00,0x00,0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G0032: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x0C,0x10,0x20,0x40,0x40,0x7E,0x00,0x00
+G0033: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x1C,0x02,0x02,0x42,0x42,0x3C,0x00,0x00
+G0034: .byte 0x00,0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x44,0x44,0x7E,0x04,0x04,0x04,0x00,0x00
+G0035: .byte 0x00,0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x02,0x02,0x02,0x42,0x3C,0x00,0x00
+G0036: .byte 0x00,0x00,0x00,0x00,0x1C,0x20,0x40,0x40,0x7C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G0037: .byte 0x00,0x00,0x00,0x00,0x7E,0x02,0x02,0x04,0x04,0x04,0x08,0x08,0x08,0x08,0x00,0x00
+G0038: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x3C,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G0039: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x3E,0x02,0x02,0x02,0x04,0x38,0x00,0x00
+G003A: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00
+G003B: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x08,0x08,0x10,0x00
+G003C: .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x02,0x00,0x00
+G003D: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00
+G003E: .byte 0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00
+G003F: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x08,0x08,0x00,0x08,0x08,0x00,0x00
+G0040: .byte 0x00,0x00,0x00,0x00,0x1C,0x22,0x4A,0x56,0x52,0x52,0x52,0x4E,0x20,0x1E,0x00,0x00
+G0041: .byte 0x00,0x00,0x00,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G0042: .byte 0x00,0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x7C,0x42,0x42,0x42,0x42,0x7C,0x00,0x00
+G0043: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x40,0x40,0x40,0x40,0x42,0x42,0x3C,0x00,0x00
+G0044: .byte 0x00,0x00,0x00,0x00,0x78,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0x78,0x00,0x00
+G0045: .byte 0x00,0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x7E,0x00,0x00
+G0046: .byte 0x00,0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x40,0x00,0x00
+G0047: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x40,0x40,0x4E,0x42,0x42,0x46,0x3A,0x00,0x00
+G0048: .byte 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x42,0x00,0x00
+G0049: .byte 0x00,0x00,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G004A: .byte 0x00,0x00,0x00,0x00,0x1F,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x44,0x38,0x00,0x00
+G004B: .byte 0x00,0x00,0x00,0x00,0x42,0x44,0x48,0x50,0x60,0x60,0x50,0x48,0x44,0x42,0x00,0x00
+G004C: .byte 0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E,0x00,0x00
+G004D: .byte 0x00,0x00,0x00,0x00,0x42,0x42,0x66,0x66,0x5A,0x5A,0x42,0x42,0x42,0x42,0x00,0x00
+G004E: .byte 0x00,0x00,0x00,0x00,0x42,0x62,0x62,0x52,0x52,0x4A,0x4A,0x46,0x46,0x42,0x00,0x00
+G004F: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G0050: .byte 0x00,0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x7C,0x40,0x40,0x40,0x40,0x40,0x00,0x00
+G0051: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x5A,0x66,0x3C,0x03,0x00
+G0052: .byte 0x00,0x00,0x00,0x00,0x7C,0x42,0x42,0x42,0x7C,0x48,0x44,0x44,0x42,0x42,0x00,0x00
+G0053: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x40,0x30,0x0C,0x02,0x42,0x42,0x3C,0x00,0x00
+G0054: .byte 0x00,0x00,0x00,0x00,0x7F,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00
+G0055: .byte 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G0056: .byte 0x00,0x00,0x00,0x00,0x41,0x41,0x41,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00
+G0057: .byte 0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x5A,0x5A,0x66,0x66,0x42,0x42,0x00,0x00
+G0058: .byte 0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x24,0x18,0x18,0x24,0x24,0x42,0x42,0x00,0x00
+G0059: .byte 0x00,0x00,0x00,0x00,0x41,0x41,0x22,0x22,0x14,0x08,0x08,0x08,0x08,0x08,0x00,0x00
+G005A: .byte 0x00,0x00,0x00,0x00,0x7E,0x02,0x02,0x04,0x08,0x10,0x20,0x40,0x40,0x7E,0x00,0x00
+G005B: .byte 0x00,0x00,0x00,0x0E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x0E,0x00
+G005C: .byte 0x00,0x00,0x00,0x00,0x40,0x40,0x20,0x10,0x10,0x08,0x08,0x04,0x02,0x02,0x00,0x00
+G005D: .byte 0x00,0x00,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00
+G005E: .byte 0x00,0x00,0x18,0x24,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G005F: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00
+G0060: .byte 0x00,0x20,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G0061: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G0062: .byte 0x00,0x00,0x00,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x62,0x5C,0x00,0x00
+G0063: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x40,0x40,0x40,0x42,0x3C,0x00,0x00
+G0064: .byte 0x00,0x00,0x00,0x02,0x02,0x02,0x3A,0x46,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00
+G0065: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00
+G0066: .byte 0x00,0x00,0x00,0x0C,0x10,0x10,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00
+G0067: .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x3A,0x44,0x44,0x44,0x38,0x20,0x3C,0x42,0x42,0x3C
+G0068: .byte 0x00,0x00,0x00,0x40,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00
+G0069: .byte 0x00,0x00,0x00,0x08,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G006A: .byte 0x00,0x00,0x00,0x04,0x04,0x00,0x0C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x48,0x30
+G006B: .byte 0x00,0x00,0x00,0x00,0x40,0x40,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x42,0x00,0x00
+G006C: .byte 0x00,0x00,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G006D: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x00,0x00
+G006E: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00
+G006F: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G0070: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x62,0x5C,0x40,0x40
+G0071: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3A,0x46,0x42,0x42,0x42,0x42,0x46,0x3A,0x02,0x02
+G0072: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x5C,0x62,0x42,0x40,0x40,0x40,0x40,0x40,0x00,0x00
+G0073: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x30,0x0C,0x02,0x42,0x3C,0x00,0x00
+G0074: .byte 0x00,0x00,0x00,0x00,0x10,0x10,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x0C,0x00,0x00
+G0075: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00
+G0076: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x00,0x00
+G0077: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x49,0x49,0x49,0x49,0x49,0x49,0x36,0x00,0x00
+G0078: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x24,0x18,0x18,0x24,0x42,0x42,0x00,0x00
+G0079: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x3C
+G007A: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x02,0x04,0x08,0x10,0x20,0x40,0x7E,0x00,0x00
+G007B: .byte 0x00,0x00,0x00,0x0C,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x0C,0x00
+G007C: .byte 0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08
+G007D: .byte 0x00,0x00,0x00,0x30,0x08,0x08,0x10,0x10,0x08,0x08,0x10,0x10,0x08,0x08,0x30,0x00
+G007E: .byte 0x00,0x00,0x00,0x31,0x49,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G007F: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x73,0xD1,0xCA,0x10,0x4B,0xD1,0xCA,0x10,0x73,0xDF,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0080: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0x9D,0xCA,0x52,0x73,0xD3,0xC2,0x52,0x42,0x5D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0081: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x49,0x9D,0xCA,0x52,0x7A,0x5D,0xCA,0x50,0x49,0x91,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0082: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x73,0x93,0xCA,0x52,0x73,0x9F,0xCA,0x12,0x72,0x13,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0083: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x4B,0x93,0xEA,0x52,0x5B,0x9F,0xCA,0x52,0x4B,0x93,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0084: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x74,0xB9,0xA6,0xA4,0x25,0xA5,0xA4,0xA4,0x74,0xB9,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0085: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x4B,0xD1,0xEA,0x10,0x5B,0xD1,0xCA,0x10,0x4B,0xDF,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0086: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xCD,0xC2,0x12,0x31,0x9F,0x88,0x52,0x73,0x93,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0087: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x79,0xCD,0xC2,0x12,0x79,0x9F,0xC0,0x52,0x7B,0x93,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0088: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x4B,0x9D,0xC9,0x20,0x79,0x19,0xC9,0x04,0x49,0x39,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0089: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x4B,0xB9,0xC9,0x08,0x79,0x09,0xC9,0x08,0x49,0x31,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G008A: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x45,0xCD,0xC4,0x90,0x44,0x89,0xA8,0x84,0x10,0x99,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G008B: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x72,0x1D,0xCA,0x12,0x72,0x13,0xC2,0x12,0x43,0xDD,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G008C: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x72,0x13,0xCA,0x12,0x72,0x13,0xC2,0x12,0x43,0xCD,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G008D: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x0E,0x21,0x89,0x20,0x0E,0x21,0x8A,0x20,0x09,0x21,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G008E: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xDD,0xC2,0x02,0x31,0x8D,0x88,0x50,0x73,0x9F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G008F: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xDD,0xC2,0x02,0x31,0x8D,0x88,0x42,0x73,0x9D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0090: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x71,0xCF,0xCA,0x10,0x4A,0x0D,0xCA,0x02,0x71,0xDD,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0091: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x72,0x45,0xCA,0x4C,0x72,0x45,0xC2,0x44,0x41,0x8F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0092: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x72,0x5D,0xCA,0x42,0x72,0x4D,0xC2,0x50,0x41,0x9F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0093: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3B,0x9D,0xC1,0x20,0x31,0x19,0x89,0x04,0x71,0x39,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0094: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xD3,0xC2,0x12,0x42,0x1F,0xC2,0x12,0x39,0xD3,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0095: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x45,0x11,0xED,0x10,0x55,0x51,0xC5,0xB0,0x45,0x11,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0096: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x3B,0x8D,0xC2,0x52,0x33,0x9F,0x8A,0x12,0x72,0x13,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0097: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x7B,0x8D,0xC2,0x52,0x7B,0x9F,0xC2,0x12,0x7A,0x13,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0098: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0x8F,0xC2,0x50,0x32,0x4D,0x8A,0x42,0x71,0x9D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G0099: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x33,0x9B,0xC4,0x22,0x25,0xA3,0x94,0xA2,0x63,0x9B,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G009A: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xDD,0xC2,0x08,0x32,0x09,0x8A,0x08,0x71,0xDD,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G009B: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x39,0xDD,0xC2,0x08,0x41,0x89,0xC0,0x48,0x3B,0x9D,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G009C: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x0E,0xF9,0x90,0x20,0x0C,0x21,0x82,0x20,0x1C,0x21,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G009D: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x31,0xCF,0xCA,0x10,0x49,0x91,0xC8,0x50,0x33,0x8F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G009E: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x72,0x21,0xCB,0x60,0x72,0xA1,0xC2,0x20,0x42,0x21,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G009F: .byte 0xAA,0xAA,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x33,0x8F,0xCA,0x50,0x7B,0x91,0xCA,0x10,0x4A,0x0F,0x80,0x00,0x00,0x01,0x80,0x00,0x00,0x01,0x80,0x00,0x55,0x55
+G00A0: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00A1: .byte 0x00,0x00,0x00,0x00,0x08,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00
+G00A2: .byte 0x00,0x00,0x00,0x00,0x08,0x08,0x3E,0x49,0x48,0x48,0x49,0x3E,0x08,0x08,0x00,0x00
+G00A3: .byte 0x00,0x00,0x00,0x00,0x0E,0x10,0x10,0x10,0x7C,0x10,0x10,0x10,0x3E,0x61,0x00,0x00
+G00A4: .byte 0x00,0x00,0x00,0x00,0x00,0x42,0x24,0x3C,0x24,0x24,0x3C,0x24,0x42,0x00,0x00,0x00
+G00A5: .byte 0x00,0x00,0x00,0x00,0x41,0x22,0x14,0x08,0x7F,0x08,0x7F,0x08,0x08,0x08,0x00,0x00
+G00A6: .byte 0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x00,0x00,0x08,0x08,0x08,0x08,0x00,0x00
+G00A7: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x3C,0x42,0x42,0x3C,0x02,0x42,0x3C,0x00,0x00
+G00A8: .byte 0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00A9: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x99,0xA5,0xA1,0xA1,0xA5,0x99,0x42,0x3C,0x00,0x00
+G00AA: .byte 0x00,0x00,0x1C,0x02,0x1E,0x22,0x1E,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00AB: .byte 0x00,0x00,0x00,0x00,0x00,0x12,0x12,0x24,0x24,0x48,0x24,0x24,0x12,0x12,0x00,0x00
+G00AC: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x02,0x02,0x02,0x00,0x00
+G00AD: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00
+G00AE: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0xB9,0xA5,0xA5,0xB9,0xA9,0xA5,0x42,0x3C,0x00,0x00
+G00AF: .byte 0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00B0: .byte 0x10,0x28,0x28,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00B1: .byte 0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x7F,0x08,0x08,0x08,0x00,0x7F,0x00,0x00,0x00
+G00B2: .byte 0x00,0x00,0x1C,0x22,0x02,0x1C,0x20,0x20,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00B3: .byte 0x00,0x00,0x1C,0x22,0x02,0x1C,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00B4: .byte 0x00,0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00B5: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x36,0x2A,0x20,0x20
+G00B6: .byte 0x00,0x00,0x00,0x3E,0x7A,0x7A,0x7A,0x7A,0x3A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0E,0x00
+G00B7: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00
+G00B8: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x30
+G00B9: .byte 0x00,0x00,0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00BA: .byte 0x00,0x00,0x1C,0x22,0x22,0x22,0x1C,0x00,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+G00BB: .byte 0x00,0x00,0x00,0x00,0x00,0x48,0x48,0x24,0x24,0x12,0x24,0x24,0x48,0x48,0x00,0x00
+G00BC: .byte 0x00,0x00,0x00,0x00,0x22,0x62,0x24,0x28,0x28,0x12,0x16,0x2A,0x4E,0x42,0x00,0x00
+G00BD: .byte 0x00,0x00,0x00,0x00,0x22,0x62,0x24,0x28,0x28,0x14,0x1A,0x22,0x44,0x4E,0x00,0x00
+G00BE: .byte 0x00,0x00,0x00,0x00,0x62,0x12,0x24,0x18,0x68,0x12,0x16,0x2A,0x4E,0x42,0x00,0x00
+G00BF: .byte 0x00,0x00,0x00,0x00,0x08,0x08,0x00,0x08,0x08,0x30,0x42,0x42,0x42,0x3C,0x00,0x00
+G00C0: .byte 0x30,0x0C,0x00,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G00C1: .byte 0x0C,0x30,0x00,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G00C2: .byte 0x18,0x24,0x00,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G00C3: .byte 0x32,0x4C,0x00,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G00C4: .byte 0x24,0x24,0x00,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G00C5: .byte 0x18,0x24,0x18,0x00,0x18,0x24,0x24,0x42,0x42,0x7E,0x42,0x42,0x42,0x42,0x00,0x00
+G00C6: .byte 0x00,0x00,0x00,0x00,0x1F,0x28,0x48,0x48,0x7F,0x48,0x48,0x48,0x48,0x4F,0x00,0x00
+G00C7: .byte 0x00,0x00,0x00,0x00,0x3C,0x42,0x42,0x40,0x40,0x40,0x40,0x42,0x42,0x3C,0x08,0x30
+G00C8: .byte 0x30,0x0C,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x7E,0x00,0x00
+G00C9: .byte 0x0C,0x30,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x7E,0x00,0x00
+G00CA: .byte 0x18,0x24,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x7E,0x00,0x00
+G00CB: .byte 0x24,0x24,0x00,0x00,0x7E,0x40,0x40,0x40,0x7C,0x40,0x40,0x40,0x40,0x7E,0x00,0x00
+G00CC: .byte 0x18,0x06,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00CD: .byte 0x0C,0x30,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00CE: .byte 0x18,0x24,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00CF: .byte 0x24,0x24,0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00D0: .byte 0x00,0x00,0x00,0x00,0x78,0x44,0x42,0x42,0xF2,0x42,0x42,0x42,0x44,0x78,0x00,0x00
+G00D1: .byte 0x32,0x4C,0x00,0x00,0x42,0x62,0x62,0x52,0x52,0x4A,0x4A,0x46,0x46,0x42,0x00,0x00
+G00D2: .byte 0x30,0x0C,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00D3: .byte 0x0C,0x30,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00D4: .byte 0x18,0x24,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00D5: .byte 0x32,0x4C,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00D6: .byte 0x24,0x24,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00D7: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x24,0x18,0x24,0x42,0x00,0x00,0x00,0x00
+G00D8: .byte 0x00,0x00,0x00,0x02,0x3A,0x44,0x46,0x4A,0x4A,0x52,0x52,0x62,0x22,0x5C,0x40,0x00
+G00D9: .byte 0x30,0x0C,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00DA: .byte 0x0C,0x30,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00DB: .byte 0x18,0x24,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00DC: .byte 0x24,0x24,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00DD: .byte 0x0C,0x30,0x00,0x00,0x41,0x41,0x22,0x22,0x14,0x08,0x08,0x08,0x08,0x08,0x00,0x00
+G00DE: .byte 0x00,0x00,0x00,0x40,0x40,0x78,0x44,0x42,0x42,0x44,0x78,0x40,0x40,0x40,0x00,0x00
+G00DF: .byte 0x00,0x00,0x00,0x00,0x38,0x44,0x44,0x44,0x7C,0x42,0x42,0x42,0x62,0x5C,0x00,0x00
+G00E0: .byte 0x00,0x00,0x30,0x0C,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G00E1: .byte 0x00,0x00,0x0C,0x30,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G00E2: .byte 0x00,0x00,0x18,0x24,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G00E3: .byte 0x00,0x00,0x32,0x4C,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G00E4: .byte 0x00,0x00,0x24,0x24,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G00E5: .byte 0x00,0x18,0x24,0x18,0x00,0x00,0x3C,0x42,0x02,0x3E,0x42,0x42,0x46,0x3A,0x00,0x00
+G00E6: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x49,0x09,0x3F,0x48,0x48,0x49,0x3E,0x00,0x00
+G00E7: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x40,0x40,0x40,0x40,0x42,0x3C,0x08,0x30
+G00E8: .byte 0x00,0x00,0x30,0x0C,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00
+G00E9: .byte 0x00,0x00,0x0C,0x30,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00
+G00EA: .byte 0x00,0x00,0x18,0x24,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00
+G00EB: .byte 0x00,0x00,0x24,0x24,0x00,0x00,0x3C,0x42,0x42,0x7E,0x40,0x40,0x42,0x3C,0x00,0x00
+G00EC: .byte 0x00,0x00,0x30,0x0C,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00ED: .byte 0x00,0x00,0x0C,0x30,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00EE: .byte 0x00,0x00,0x18,0x24,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00EF: .byte 0x00,0x00,0x24,0x24,0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00
+G00F0: .byte 0x00,0x00,0x32,0x0C,0x14,0x22,0x02,0x3E,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00F1: .byte 0x00,0x00,0x32,0x4C,0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42,0x42,0x42,0x00,0x00
+G00F2: .byte 0x00,0x00,0x30,0x0C,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00F3: .byte 0x00,0x00,0x0C,0x30,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00F4: .byte 0x00,0x00,0x18,0x24,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00F5: .byte 0x00,0x00,0x32,0x4C,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00F6: .byte 0x00,0x00,0x24,0x24,0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,0x00,0x00
+G00F7: .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x7E,0x00,0x00,0x18,0x00,0x00,0x00
+G00F8: .byte 0x00,0x00,0x00,0x00,0x00,0x02,0x3C,0x46,0x4A,0x4A,0x52,0x52,0x62,0x3C,0x40,0x00
+G00F9: .byte 0x00,0x00,0x30,0x0C,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00
+G00FA: .byte 0x00,0x00,0x0C,0x30,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00
+G00FB: .byte 0x00,0x00,0x18,0x24,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00
+G00FC: .byte 0x00,0x00,0x24,0x24,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3A,0x00,0x00
+G00FD: .byte 0x00,0x00,0x0C,0x30,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x3C
+G00FE: .byte 0x00,0x00,0x00,0x00,0x20,0x20,0x3C,0x22,0x22,0x22,0x24,0x28,0x30,0x20,0x20,0x20
+G00FF: .byte 0x00,0x00,0x24,0x24,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x3C
+
diff --git a/Marmot/forth.c b/Marmot/forth.c
new file mode 100644
index 0000000..e42e3de
--- /dev/null
+++ b/Marmot/forth.c
@@ -0,0 +1,23 @@
+/*
+ * forth.c --
+ *
+ * Forth interpreter.
+ */
+
+
+#define MAXWORDLEN 255
+
+
+
+
+void
+ForthMain(void)
+{
+ char c, *tokStart, *tokEnd;
+
+ while (1) {
+
+
+
+ }
+}
diff --git a/Marmot/hexfont2data.pl b/Marmot/hexfont2data.pl
new file mode 100644
index 0000000..fdb2a79
--- /dev/null
+++ b/Marmot/hexfont2data.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+#
+# hexfont2data.pl --
+#
+# Convert a font hex file (http://unifoundry.com/unifont.html) to
+# a .data section suitable for assembly by gas.
+
+use strict;
+use warnings;
+
+my $in = *STDIN;
+my $out = *STDOUT;
+
+if (@ARGV == 0) {
+ # nop
+} elsif (@ARGV == 2) {
+ open $in, "<$ARGV[0]" or die "Unable to read $ARGV[0]: $!\n";
+ open $out, ">$ARGV[1]" or die "Unable to write $ARGV[1]: $!\n";
+} elsif (@ARGV == 1) {
+ my $type;
+
+ if (-e $ARGV[0] and (stat($ARGV[0]))[7]) {
+ $type = 'input';
+ open $in, "<$ARGV[0]" or die "Unable to read $ARGV[0]: $!\n";
+ } else {
+ $type = 'output';
+ open $out, ">$ARGV[0]" or die "Unable to write $ARGV[0]: $!\n";
+ }
+
+ print STDERR "Warning: ambiguous arguments. Assuming $ARGV[0] is $type\n";
+} else {
+ die <<"USAGE";
+Usage: hexfont2data.pl [input] [output]
+USAGE
+}
+
+my $table = '';
+my $data = '';
+my $c = 0;
+
+while (my $line = <$in>) {
+ chomp $line;
+ $c++;
+
+ unless ($line =~ m/^(....):(.+)/) {
+ print STDERR "Warning: Invalid line $c\n";
+ next;
+ }
+
+ my ($n, $bmp) = ($1, $2);
+ my ($width, $height);
+
+ my $length = length($bmp) / 2;
+
+ # XXX: I count 32 and 64, but Perl counts 16 and 32(!). I'm baffled.
+ if ($length == 16) {
+ $width = 8;
+ $height = 16;
+ } elsif ($length == 32) {
+ $width = 16;
+ $height = 16;
+ }
+
+ $table .= <<"TABLE_ENTRY";
+ .long G$n
+ .word $width, $height
+TABLE_ENTRY
+
+ my $bytes = "G$n: .byte ";
+ while ($bmp =~ m/(..)/g) {
+ $bytes .= "0x$1,";
+ }
+ chop $bytes; # remove trailing comma
+
+ $data .= "$bytes\n";
+}
+
+print $out <<"DATA";
+ .section .data
+ .align 8
+ .global fontTable
+fontTable:
+$table
+
+ .align 4
+$data
+DATA
diff --git a/Marmot/interrupts.S b/Marmot/interrupts.S
new file mode 100644
index 0000000..a9ab123
--- /dev/null
+++ b/Marmot/interrupts.S
@@ -0,0 +1,126 @@
+ /*
+ * interrupts.S
+ *
+ * Interrupt handlers.
+ *
+ */
+
+#define ASM
+#include <marmot.h>
+
+ .macro SaveGP
+ pushq %rax
+ pushq %rbx
+ pushq %rcx
+ pushq %rdx
+ pushq %rbp
+ pushq %rsi
+ pushq %rdi
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ .endm
+
+ .macro RestoreGP
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rdi
+ popq %rsi
+ popq %rbp
+ popq %rdx
+ popq %rcx
+ popq %rbx
+ popq %rax
+ .endm
+
+
+ .macro FatalWithCode name
+ .global \name
+\name: jmp Fatal64
+ .endm
+
+ .macro FatalNoCode name
+ .global \name
+\name: pushq $0
+ jmp Fatal64
+ .endm
+
+ .macro DumpIH name
+ .global \name
+\name: pushq $0
+ call Dump64
+ iretq
+ .endm
+
+ .macro SpringboardWithCode name landing
+ .global \name
+\name: SaveGP
+ leaq (15 * 16)(%rsp), %rdi
+ call \landing
+ RestoreGP
+ addq $8, %rsp
+ iretq
+ .endm
+
+ .macro irqm irq name
+ .global _IRQStub_\name
+_IRQStub_\name:
+ cld
+ SaveGP
+ movl $\irq, %edi
+ call DoIRQ
+ RestoreGP
+ iretq
+ .endm
+
+
+ .section .text
+ .code64
+
+ /* processor fault/exception handlers */
+
+ FatalNoCode DE64
+ DumpIH DB64
+ DumpIH NMI64
+ DumpIH BP64
+ DumpIH OF64
+ FatalNoCode BR64
+ FatalNoCode UD64
+ FatalNoCode NM64
+ FatalWithCode DF64
+ /* vector 9 is not used */
+ FatalWithCode TS64
+ FatalWithCode NP64
+ FatalWithCode SS64
+ FatalWithCode GP64
+ SpringboardWithCode PF64 HandlePF
+ /* vector 15 is not used */
+ FatalNoCode MF64
+ FatalWithCode AC64
+ FatalNoCode MC64
+ FatalNoCode XF64
+ /* 20-31 are reserved */
+
+ irqm PIT_IRQ PIT
+ irqm KBD_IRQ KBD
+ irqm RTC_IRQ RTC
+ irqm MOUSE_IRQ MOUSE
+
+Dump64: ret
+
+ .global Fatal64
+Fatal64:
+ call Dump64
+1: hlt
+ jmp 1b
diff --git a/Marmot/irq.c b/Marmot/irq.c
new file mode 100644
index 0000000..9502034
--- /dev/null
+++ b/Marmot/irq.c
@@ -0,0 +1,711 @@
+/*
+ * irq.c --
+ *
+ * Generic IRQ handler.
+ */
+
+#include <marmot.h>
+
+
+struct tod {
+ uint8 hour;
+ uint8 minute;
+ uint8 second;
+} __attribute__((packed));
+
+struct tod tod;
+
+
+
+#define KBD_REG_STATUS 0x64
+#define KBD_STATUS_OUT_DATA (1 << 0)
+#define KBD_STATUS_IN_DATA (1 << 1)
+#define KBD_STATUS_SYSFLAG (1 << 2)
+#define KBD_STATUS_INDATA_CMD (1 << 3)
+#define KBD_STATUS_ENABLE (1 << 4)
+#define KBD_STATUS_XMIT_TIMEOUT (1 << 5)
+#define KBD_STATUS_AUX_DATA (1 << 5)
+#define KBD_STATUS_RECV_TIMEOUT (1 << 6)
+#define KBD_STATUS_PARITY_EVEN (1 << 7)
+
+#define KBD_CMD_KBDIRQ 0x01
+#define KBD_CMD_AUXIRQ 0x02
+#define KBD_CMD_KBDDIS 0x10
+#define KBD_CMD_AUXDIS 0x20
+#define KBD_CMD_XLATE 0x40
+
+
+#define KBD_REG_COMMAND 0x64
+#define KBD_REG_DATA 0x60
+
+#define MOUSE_ACK 0xfa
+
+
+#define RTC_PORT_ADDR 0x70
+#define RTC_PORT_DATA 0x71
+
+#define RTC_SEC 0x00
+#define RTC_ASEC 0x01
+#define RTC_MIN 0x02
+#define RTC_AMIN 0x03
+#define RTC_HOUR 0x04
+#define RTC_AHOUR 0x05
+#define RTC_DOW 0x06
+#define RTC_DOM 0x07
+#define RTC_MON 0x08
+#define RTC_YEAR 0x09
+
+#define RTC_REG_A 0x0a
+#define RTC_REG_A_RATE 0x0f
+#define RTC_REG_A_DIV 0x70
+#define RTC_REG_A_UIP 0x80
+
+#define RTC_REG_B 0x0b
+#define RTC_REG_B_DST (1 << 0)
+#define RTC_REG_B_24H (1 << 1)
+#define RTC_REG_B_BIN (1 << 2)
+#define RTC_REG_B_SQE (1 << 3)
+#define RTC_REG_B_UIE (1 << 4)
+#define RTC_REG_B_AIE (1 << 5)
+#define RTC_REG_B_PIE (1 << 6)
+#define RTC_REG_B_DCU (1 << 7)
+
+#define RTC_REG_C 0x0c
+#define RTC_REG_C_UIE (1 << 4)
+#define RTC_REG_C_AIE (1 << 5)
+#define RTC_REG_C_PIE (1 << 6)
+#define RTC_REG_C_IRQF (1 << 7)
+
+#define RTC_REG_D
+#define RTC_REG_D_RAMP (1 << 7)
+
+#define BCD_TO_BIN(b) (((((b) >> 4) & 0xf) * 10) + ((b) & 0xf))
+
+
+void
+MaskPIC(uint8 irq)
+{
+ uint8 mask, port;
+
+ if (irq > 7) {
+ irq -= 8;
+ port = 0xa1;
+ } else {
+ port = 0x21;
+ }
+
+ mask = inb(port);
+ mask |= (1 << irq);
+ outb(mask, port);
+}
+
+void
+UnmaskPIC(uint8 irq)
+{
+ uint8 mask;
+
+ if (irq > 7) {
+ mask = inb(0xa1);
+ mask &= ~(1 << (irq - 8));
+ outb(mask, 0xa1);
+
+ irq = 2;
+ }
+
+ mask = inb(0x21);
+ mask &= ~(1 << irq);
+ outb(mask, 0x21);
+}
+
+void
+AckPIC(uint8 irq)
+{
+ if (irq > 7) {
+ outb(0x60 | (irq - 8), 0xa0);
+ irq = 2;
+ }
+
+ outb(0x60 | irq, 0x20);
+}
+
+
+
+
+CbID
+GetCBId(void)
+{
+ static uint64 curID = 0;
+
+ /*
+ * XXX: One day this should be a little more robust than a one-up.
+ */
+
+ return ++curID;
+}
+
+static struct MouseCB *mouseCB;
+
+CbID
+InstallMouseCB(MouseCBFun cb)
+{
+ struct MouseCB *new;
+
+ new = alloc(sizeof(struct MouseCB));
+ new->next = mouseCB;
+ new->id = GetCBId();
+ new->cb = cb;
+
+ mouseCB = new;
+
+ return new->id;
+}
+
+void
+RemoveMouseCB(CbID id)
+{
+ struct MouseCB *s, *del = NULL;
+
+ ASSERT(mouseCB != NULL);
+
+ /* Shouldn't need a lock here */
+ if (mouseCB->id == id) {
+ s = mouseCB;
+ mouseCB = s->next;
+ del = s;
+ } else {
+ for (s = mouseCB; s->next != NULL; s = s->next) {
+ if (s->next->id == id) {
+ del = s->next;
+ s->next = s->next->next;
+ break;
+ }
+ }
+ }
+
+ ASSERT(del != NULL);
+ bzero(del, sizeof(struct MouseCB));
+ free(del);
+}
+
+
+void
+InstallIDTEntry(uint64 vec, void (*stub)(void))
+{
+ uint64 *idt = (uint64 *)IDT;
+ VA stubAddr = (VA)stub;
+
+ *(idt + 2 * vec) = (((stubAddr & 0xffff0000) << 32) |
+ 0x8e0100000000 |
+ ((CS64 & 0xffff) << 16) |
+ (stubAddr & 0xffff));
+ *(idt + 2 * vec + 1) = (stubAddr >> 32) & 0xffffffff;
+}
+
+
+void
+DisplayClock(void)
+{
+ Point p0, p1;
+ char time[] = { ' ', ' ', ':', ' ', ' ', ':', ' ', ' ', 0 };
+
+ time[0] = tod.hour / 10 + '0';
+ time[1] = tod.hour % 10 + '0';
+ time[3] = tod.minute / 10 + '0';
+ time[4] = tod.minute % 10 + '0';
+ time[6] = tod.second / 10 + '0';
+ time[7] = tod.second % 10 + '0';
+
+ p1.x = xResolution - 4;
+ p1.y = yResolution - 4;
+
+ p0.x = p1.x - 8 * 8;
+ p0.y = p1.y - 16;
+
+ ColorRectangle(COLOR_PLEASING_GREEN, p0, p1);
+ PrintMessage(COLOR_BLACK, p0, time);
+}
+
+void
+UpdateClock(void)
+{
+ /* ACK the interrupt */
+ outb(RTC_REG_C, RTC_PORT_ADDR);
+ inb(RTC_PORT_DATA);
+
+ /* update the time of day */
+ if (++tod.second >= 60) {
+ tod.second = 0;
+ if (++tod.minute >= 60) {
+ tod.minute = 0;
+ if (++tod.hour >= 24) {
+ tod.hour = 0;
+ }
+ }
+ }
+}
+
+
+static inline void
+KbdWaitWrite(void)
+{
+ while (inb(KBD_REG_STATUS) & KBD_STATUS_IN_DATA); // 0x2
+}
+
+static inline void
+KbdWaitRead(void)
+{
+ while (~inb(KBD_REG_STATUS) & KBD_STATUS_OUT_DATA); // 0x1
+}
+
+uint8
+ReadKeyboard(void)
+{
+ KbdWaitRead();
+ return inb(KBD_REG_DATA);
+}
+
+
+void
+ClearKeyDisplay(void)
+{
+ Point p0, p1;
+
+ p0.x = 4;
+ p0.y = yResolution - 4 - 16;
+
+ p1.x = 4 + 8 * 16; // max of 16 16 pix wide chars
+ p1.y = yResolution - 4;
+
+ ColorRectangle(COLOR_PLEASING_GREEN, p0, p1);
+}
+
+char keys[8];
+uint64 keyp;
+
+#define lbHex(b) ((((b) & 0xf) < 0xa) ? \
+ ((b) & 0xf) + '0' : \
+ (((b) & 0xf) - 0xa) + 'a')
+#define hbHex(b) (lbHex((b) >> 4))
+
+void
+DisplayKeycode(void)
+{
+ Point p;
+ char c[17];
+ uint64 k;
+
+ bzero(c, 17);
+
+ for (k = 0; k < keyp; k++) {
+ c[2 * k] = hbHex(keys[k]);
+ c[2 * k + 1] = lbHex(keys[k]);
+ }
+
+ p.x = 4;
+ p.y = yResolution - 4 - 16;
+
+ PrintMessage(COLOR_BLACK, p, c);
+}
+
+
+/*
+ * HaveCompleteScancode --
+ *
+ * Check that a fully formed mode 2 raw scancode has been received.
+ */
+
+static inline int
+HaveCompleteScancode(void)
+{
+ /*
+ * ..
+ * f0 ..
+ * e0 ..
+ * e0 f0 ..
+ * e1 .. ..
+ * e1 f0 .. f0 ..
+ */
+
+ if (keys[0] == 0xe0) {
+ if (keyp == 1 || (keyp == 2 && keys[1] == 0xf0)) {
+ return 0;
+ }
+ } else if (keys[0] == 0xe1) {
+ if (keyp < 3 || (keyp == 3 && keys[1] == 0xf0) || keyp == 4) {
+ return 0;
+ }
+ } else if (keys[0] == 0xf0 && keyp == 1) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Keyboard --
+ *
+ * Handle the keyboard interrupt.
+ */
+
+void
+Keyboard(uint8 data)
+{
+ keys[keyp++] = data;
+
+ if (HaveCompleteScancode()) {
+ ClearKeyDisplay();
+ DisplayKeycode();
+
+ bzero(keys, sizeof(keys));
+ keyp = 0;
+ }
+}
+
+
+uint8 mouse[8];
+uint64 mousep;
+uint64 mousePacketLength;
+
+
+void
+MousePacketDisplay(uint8 *packet, uint64 N)
+{
+ Point p0, p1;
+ char s[17];
+ uint64 k;
+
+ bzero(s, sizeof(s));
+
+ p0.x = 4;
+ p0.y = yResolution - 8 - 32;
+ p1.x = 4 + 8 * 8;
+ p1.y = p0.y + 16;
+ ColorRectangle(COLOR_PLEASING_GREEN, p0, p1);
+
+ for (k = 0; k < N; k++) {
+ s[2 * k] = hbHex(packet[k]);
+ s[2 * k + 1] = lbHex(packet[k]);
+ }
+
+ PrintMessage(COLOR_BLACK, p0, s);
+}
+
+
+void
+Mouse(uint8 data)
+{
+ mouse[mousep++] = data;
+
+ if (mousep == mousePacketLength) {
+ struct MouseCB *s;
+
+ for (s = mouseCB; s != NULL; s = s->next) {
+ s->cb(mouse, mousep);
+ }
+
+ bzero(mouse, sizeof(mouse));
+ mousep = 0;
+ }
+}
+
+
+void
+i8042(void)
+{
+ uint8 status, data;
+
+ status = inb(KBD_REG_STATUS);
+ if (!(status & KBD_STATUS_OUT_DATA)) {
+ return;
+ }
+
+ data = inb(KBD_REG_DATA);
+
+ if (status & KBD_STATUS_AUX_DATA) {
+ Mouse(data);
+ } else {
+ Keyboard(data);
+ }
+}
+
+
+/*
+ * _IRQPrint --
+ *
+ * Display an indicator of received interrupts.
+ */
+
+static void
+_IRQPrint(uint64 irq)
+{
+ /* Not reentrant, but that isn't important here. */
+ static int counts[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ char s[] = { 'I', 'R', 'Q', ' ', '(', ' ', ')', 0 };
+ char c[] = { '-', '\\', '|', '/' };
+ int count = 0;
+ Point p0, p1;
+
+ if (count < 16) {
+ count = counts[irq]++;
+ } else {
+ count = counts[16]++;
+ }
+
+ s[3] = (irq < 0xa) ? irq + 0x30 : irq - 0xa + 'a';
+ s[5] = c[count % sizeof(c)];
+
+ p0.x = 10;
+
+ if (irq <= 0xf) {
+ p0.y = 30 + irq * 18;
+ } else {
+ p0.y = 30 + 16 * 18;
+ }
+
+ p1.x = p0.x + 8 * 8;
+ p1.y = p0.y + 16;
+
+ ColorRectangle(COLOR_PLEASING_GREEN, p0, p1);
+ PrintMessage(COLOR_BLACK, p0, s);
+}
+
+
+void
+DoIRQ(uint64 irq)
+{
+ _IRQPrint(irq - 0x20);
+
+ MaskPIC(irq - 0x20);
+ AckPIC(irq - 0x20);
+
+ switch (irq) {
+ case PIT_IRQ:
+ TaskSchedule(irq); // does not return
+ break;
+ case KBD_IRQ:
+ case MOUSE_IRQ:
+ i8042();
+ break;
+ case RTC_IRQ:
+ UpdateClock();
+ DisplayClock();
+ break;
+ }
+
+ UnmaskPIC(irq - 0x20);
+}
+
+
+#define PIT_C0 0x40
+#define PIT_C1 0x41
+#define PIT_C2 0x42
+#define PIT_CW 0x43
+
+/*
+ * Actually 1193181.666... but this isn't used for keeping time to the
+ * round off error isn't significant (and it's doubtful the clock is
+ * that accurate anyways).
+ */
+#define PIT_CLK_FREQ 1193182
+#define PIT_COUNTDOWN (PIT_CLK_FREQ / TICK_Hz)
+
+#define PIT_CW_BIN 0x00
+#define PIT_CW_BCD 0x01
+#define PIT_CW_MODE0 0x00
+#define PIT_CW_MODE1 0x02
+#define PIT_CW_MODE2 0x04
+#define PIT_CW_MODE3 0x06
+#define PIT_CW_MODE4 0x08
+#define PIT_CW_MODE5 0x0a
+#define PIT_CW_RW_LATCH 0x00
+#define PIT_CW_RW_LSB 0x10
+#define PIT_CW_RW_MSB 0x20
+#define PIT_CW_RW_LSBMSB 0x30
+#define PIT_CW_CTR0 0x00
+#define PIT_CW_CTR1 0x40
+#define PIT_CW_CTR2 0x80
+#define PIT_CW_READBACK 0xc0
+
+
+void
+StartPIT(void)
+{
+ uint16 tick;
+
+ /*
+ * Set the PIT to TICK_Hz.
+ */
+
+ tick = PIT_COUNTDOWN;
+ outb(PIT_CW_BIN | PIT_CW_MODE2 | PIT_CW_RW_LSBMSB | PIT_CW_CTR0, PIT_CW);
+ outb(tick & 0xff, PIT_C0);
+ outb(tick >> 8, PIT_C0);
+
+ InstallIDTEntry(PIT_IRQ, _IRQStub_PIT);
+ UnmaskPIC(PIT_IRQ - 0x20);
+}
+
+
+void
+StartClock(void)
+{
+ /*
+ * Disable daylight savings, enable 24 hour clock, and enable
+ * update ended interrupt.
+ */
+
+ outb(RTC_REG_B, RTC_PORT_ADDR);
+ outb(RTC_REG_B_24H | RTC_REG_B_UIE, RTC_PORT_DATA);
+
+ /*
+ * Initialize the clock.
+ */
+
+ do {
+ outb(RTC_REG_A, RTC_PORT_ADDR);
+ if ((inb(RTC_PORT_DATA) & RTC_REG_A_UIP) == 0) {
+ break;
+ }
+ } while (1);
+
+ outb(RTC_SEC, RTC_PORT_ADDR);
+ tod.second = BCD_TO_BIN(inb(RTC_PORT_DATA));
+ outb(RTC_MIN, RTC_PORT_ADDR);
+ tod.minute = BCD_TO_BIN(inb(RTC_PORT_DATA));
+ outb(RTC_HOUR, RTC_PORT_ADDR);
+ tod.hour = BCD_TO_BIN(inb(RTC_PORT_DATA));
+
+ DisplayClock();
+
+ /* enable in PIC */
+ InstallIDTEntry(RTC_IRQ, _IRQStub_RTC);
+ UnmaskPIC(RTC_IRQ - 0x20);
+}
+
+
+void
+i8042_WriteCmd(uint8 cmd)
+{
+ KbdWaitWrite();
+ outb(cmd, KBD_REG_COMMAND);
+}
+
+uint8
+i8042_ReadData(void)
+{
+ //KbdWaitRead();
+ return inb(KBD_REG_DATA);
+}
+
+void
+i8042_WriteData(uint8 data)
+{
+ KbdWaitWrite();
+ outb(data, KBD_REG_DATA);
+}
+
+void
+KeyboardInit(void)
+{
+ uint8 cmd;
+
+ /* Get keyboard command register. */
+ i8042_WriteCmd(0x20);
+ cmd = i8042_ReadData();
+
+ /* Enable keyboard. */
+ cmd &= ~KBD_CMD_KBDDIS;
+ cmd |= KBD_CMD_KBDIRQ;
+
+ i8042_WriteCmd(0x60);
+ i8042_WriteData(cmd);
+
+ /* Set keyboard mode 2. */
+ i8042_WriteData(0xf0);
+ i8042_WriteData(0x02);
+
+ /* Clear keyboard buffer. */
+
+ bzero(keys, sizeof(keys));
+ keyp = 0;
+
+ /* Install handler. */
+ InstallIDTEntry(KBD_IRQ, _IRQStub_KBD);
+ UnmaskPIC(KBD_IRQ - 0x20);
+}
+
+
+uint8
+i8042_WriteAuxCmd(uint8 cmd)
+{
+ KbdWaitWrite();
+ outb(0xd4, KBD_REG_COMMAND);
+ KbdWaitWrite();
+ outb(cmd, KBD_REG_DATA);
+
+ return inb(KBD_REG_DATA);
+}
+
+void
+MouseInit(void)
+{
+ uint8 cmd, data;
+
+ /* Get keyboard command register. */
+ i8042_WriteCmd(0x20);
+ cmd = i8042_ReadData();
+
+ /* Enable PS/2 mouse. */
+ cmd &= ~KBD_CMD_KBDDIS;
+ cmd |= KBD_CMD_KBDIRQ;
+
+ i8042_WriteCmd(0x60);
+ i8042_WriteData(cmd);
+
+ i8042_WriteData(0xa8);
+
+ /* Check for intellimouse extension */
+ i8042_WriteAuxCmd(0xf3);
+ i8042_WriteAuxCmd(200);
+ i8042_WriteAuxCmd(0xf3);
+ i8042_WriteAuxCmd(100);
+ i8042_WriteAuxCmd(0xf3);
+ i8042_WriteAuxCmd(80);
+
+ i8042_WriteAuxCmd(0xf2);
+ data = inb(KBD_REG_DATA);
+
+ if (data == 0x03) {
+ mousePacketLength = 4;
+ } else {
+ mousePacketLength = 3;
+ }
+
+ /* Set sample rate */
+ i8042_WriteAuxCmd(0xf3);
+ i8042_WriteAuxCmd(MOUSE_SAMPLE_RATE);
+
+ /* Set stream mode */
+ i8042_WriteAuxCmd(0xea); // set stream mode
+
+ /* Set resolution */
+ i8042_WriteAuxCmd(0xe8);
+ i8042_WriteAuxCmd(3);
+
+ /* set scaling */
+ i8042_WriteAuxCmd(0xe7);
+
+ /* Enable data reporting */
+ i8042_WriteAuxCmd(0xf4); // enable data reporting
+
+ bzero(mouse, sizeof(mouse));
+ mousep = 0;
+
+ mouseCB = NULL;
+
+ InstallMouseCB(MousePacketDisplay);
+
+ /* Install mouse interrupt handler. */
+ InstallIDTEntry(MOUSE_IRQ, _IRQStub_MOUSE);
+ UnmaskPIC(MOUSE_IRQ - 0x20);
+}
diff --git a/Marmot/ld.conf b/Marmot/ld.conf
new file mode 100644
index 0000000..74f1284
--- /dev/null
+++ b/Marmot/ld.conf
@@ -0,0 +1,26 @@
+/* ld configuration script for Marmot */
+
+
+OUTPUT_FORMAT(binary)
+
+SECTIONS
+{
+ .bss 0x6000 : { *(.bss) }
+
+ .boot 0x7c00 : AT(0) { boot.o(.boot) }
+ .boot_bss 0x7e00 : AT(SIZEOF(.boot)) { boot.o(.boot_bss) }
+ .tss 0x7f00 : AT(SIZEOF(.boot)) { loader.o(.tss) }
+
+ .loader 0x8000 : AT(SIZEOF(.boot)) { *(.loader) }
+ .text ALIGN(16) : { *(.text) }
+ .data ALIGN(16) : { *(.data) }
+ .rodata ALIGN(16) : { *(.rodata) }
+
+ /DISCARD/ : { *(.eh_*) *(.comment*) *(.note*) }
+}
+
+code_start = 0x8000 + LOADADDR(.text) - 0x200;
+code_end = ALIGN(0x8000 + LOADADDR(.rodata) + SIZEOF(.rodata) - 0x200, 16);
+
+bss_start = ADDR(.bss);
+bss_end = ALIGN(ADDR(.bss) + SIZEOF(.bss), 256);
diff --git a/Marmot/loader.S b/Marmot/loader.S
new file mode 100644
index 0000000..18be70e
--- /dev/null
+++ b/Marmot/loader.S
@@ -0,0 +1,957 @@
+ /*
+ * loader.S --
+ *
+ * OS loader for marmot. Tasks done here (in no particular
+ * order):
+ *
+ * set up protected mode data structures
+ * build memory map
+ * set up initial page tables
+ * switch to 64 bit mode
+ * set up timer devices
+ * install disk drivers
+ *
+ */
+
+#define ASM
+#include <marmot.h>
+
+ .section .loader, "xa"
+ .code16
+
+ .global Loader
+Loader:
+ call ZeroBSS
+
+ call MapE820
+ call GetVESAInfo
+ .global HaveVESA
+HaveVESA:
+ /* VESA error message is already in %si */
+ jc RealModeFlamingDeath
+
+ /* enter protected mode */
+ call EnableA20
+ cli
+ call MaskNMI16
+
+ call LoadGDT
+
+ movl %cr0, %eax
+ orb $1, %al /* CR0.PE => 1 */
+ movl %eax, %cr0
+
+ .code32
+ .byte 0x66 /* technically still in 16 bit mode */
+ ljmp $CS32, $IntoProtectedMode
+ .code16
+
+
+ /****** Real mode subroutines ******/
+
+ /*
+ * RealModeFlamingDeath --
+ *
+ * Print an error message and reboot.
+ *
+ */
+
+ .global RealModeFlamingDeath
+RealModeFlamingDeath:
+ mov $0x0e, %ah
+ mov $0x0100, %bx
+1: lodsb
+ test %al, %al
+ jz 1f
+ int $0x10
+ jmp 1b
+
+ /* wait for keypress, then reboot */
+1: xorw %ax, %ax
+ int $0x16
+ int $0x19
+
+ /* should never be reached */
+ cli
+ hlt
+
+
+ /*
+ * ZeroBSS --
+ *
+ * Zero out all bytes in .bss.
+ */
+ZeroBSS:
+ xorw %ax, %ax
+ movw %ax, %es
+ movl bss_start, %edi
+ movl bss_end, %ecx
+ subl %edi, %ecx
+ cld
+ repnz stosb
+ ret
+
+
+ /*
+ * MapE820 --
+ *
+ * Get the memory map from the BIOS using int 15,e820.
+ *
+ */
+
+MapE820:
+ xorl %ebx, %ebx
+ movl %ebx, e820_entries
+ mov %bx, %es
+ movw $e820_map, %di
+
+map_loop:
+ movl $0xe820, %eax
+ movl $20, %ecx
+ movl $SMAP, %edx
+ int $0x15
+ jc 1f
+
+ test %ebx, %ebx
+ jz 1f
+
+ addw $20, %di
+ incl e820_entries
+
+ cmpl $SMAP, %eax
+ je map_loop
+
+ /* no "SMAP" */
+ mov $bad_e820, %si
+ pushw $RealModeFlamingDeath
+
+1: ret
+
+
+ /*
+ * EnableA20 --
+ *
+ */
+
+EnableA20:
+ /* Just do this the old fashioned way, via the kbd controller. */
+ call kbd8042_ready
+ movb $0xd1, %al
+ outb %al, $0x64
+ call kbd8042_ready
+ movb $0xdf, %al
+ outb %al, $0x60
+ call kbd8042_ready
+ ret
+
+kbd8042_ready:
+ inb $0x64, %al
+ test $2, %al
+ jnz kbd8042_ready
+ ret
+
+
+ /*
+ * MaskNMI16 --
+ *
+ * 16 bit version of MaskNMI.
+ *
+ */
+
+MaskNMI16:
+ pushw %ax
+ inb $0x70, %al
+ andb $0x7f, %al
+ outb %al, $0x70
+ inb $0x71, %al
+ popw %ax
+ ret
+
+
+ /*
+ * LoadGDT --
+ *
+ * Move the GDT into its place in memory and issue lgdt.
+ */
+
+LoadGDT:
+ movw $GDTStart, %si
+ movw $GDT, %di
+ movw $(GDTEnd - GDTStart), %cx
+ rep movsb
+ movl $GDT, DTLocation
+ movw $(GDTEnd - GDTStart), DTSize
+ lgdt DTSize
+ ret
+
+
+
+ /****** Protected mode code ******/
+
+ .code32
+ .global IntoProtectedMode
+IntoProtectedMode:
+
+ movl $DS, %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+ movl $STACKTOP, %eax
+ movl %eax, %esp
+
+ xorl %eax, %eax
+ pushl %eax
+ popf
+
+ /* Remap IRQs and set up IDT */
+ call LoadIDT
+# .global IDTDone
+#IDTDone:
+ call RemapIRQs
+
+ /* Get CPUID info and verify 64 bit support */
+ call Check64_OK
+ jc 1f
+
+ /* no 64 bit mode? bail */
+ # XXX
+ cli
+ hlt
+
+
+ /* Look for other processors (startup IPI will be sent later) */
+1: call FindMPConfig
+ .global HaveMPConfig
+HaveMPConfig:
+
+ /* Set up initial page tables and enter long mode */
+
+ call InitialPageSetup
+ .global PageDone
+PageDone:
+
+ /* turn PAE on */
+ xorl %eax, %eax
+ orl $(1 << 5), %eax
+ movl %eax, %cr4
+
+ /* load PML4 */
+ movl $PML4BASE, %eax
+ movl %eax, %cr3
+
+ /* set EFER.LME */
+ movl $EFER, %ecx
+ rdmsr
+ btsl $EFER_LME, %eax
+ btsl $EFER_NXE, %eax
+ wrmsr
+
+ /* turn on paging and move into long mode */
+ movl %cr0, %eax
+ orl $0x80000000, %eax
+ movl %eax, %cr0
+
+ /* jump to 64 bit CS */
+ pushl $CS64
+ pushl $IntoLongMode
+ lret
+
+
+ /*
+ * LoadIDT --
+ *
+ * Build the IDT and issue lidt.
+ *
+ */
+
+LoadIDT:
+ /* first zero out the entire 64 bit IDT area */
+ movl $IDT, %edi
+ movl $((GDT - IDT) >> 2), %ecx
+1: movl $0, -4(%edi,%ecx,4)
+ loop 1b
+
+
+ /* make a trap gate for #0-19d */
+ movl $20, %ecx
+ movl $(IDT + 20 * 16), %edi /* offset into IDT */
+TrapLoop:
+ movl (IDTJumpTable-4)(,%ecx,4), %edx
+ /* low dword */
+ movl $(CS64 << 16), %eax
+ movw %dx, %ax
+ movl %eax, -16(%edi)
+ /* high dword */
+ movw $0x8f02, %dx
+ movl %edx, -12(%edi)
+ /* extended low */
+ xorl %eax, %eax
+ movl %eax, -8(%edi)
+ /* extended high */
+ movl %eax, -4(%edi)
+
+ subl $16, %edi
+ loop TrapLoop
+
+ /* NMI (2), DF (8), and MC (18) use IST 3 instead of 2 */
+ orb $1, (16 * 2 + 4)(%edi)
+ orb $1, (16 * 8 + 4)(%edi)
+ orb $1, (16 * 18 + 4)(%edi)
+
+ /* load the new IDT */
+
+ movl $IDT, DTLocation
+ movw $(GDT - IDT), DTSize
+ lidt DTSize
+
+ ret
+
+
+ /*
+ * RemapIRQs --
+ *
+ * Remap IRQs to start at 0x20, masking all 16. Gate
+ * installation and IRQ unmasking is done later in irq.c.
+ */
+
+RemapIRQs:
+ /* ICW1 */
+ movb $0x11, %al /* need ICW4 */
+ outb %al, $0x20
+ outb %al, $0xa0
+ /* ICW2 */
+ movb $0x20, %al
+ outb %al, $0x21 /* map master to 0x20-0x27 */
+ orb $8, %al
+ outb %al, $0xa1 /* map slave to 0x28-0x2f */
+ /* ICW3 */
+ movb $4, %al
+ outb %al, $0x21 /* master IRQ2 cascades to slave */
+ movb $2, %al
+ outb %al, $0xa1 /* slave to IRQ2 */
+ /* ICW4 */
+ movb $1, %al /* 80x86 mode */
+ outb %al, $0x21
+ outb %al, $0xa1
+ /* done - mask all interrupts */
+
+ movb $0xff, %al
+ outb %al, $0x21
+ outb %al, $0xa1
+
+ ret
+
+
+InitialPageSetup:
+ movl $PML4BASE, %esi
+1: movl $0, (%esi)
+ addl $4, %esi
+ cmpl $PAGETOP, %esi
+ jb 1b
+
+ xorl %ecx, %ecx /* ecx is the address of the current page */
+ xorl %edx, %edx /* edx is the top 4 bytes of table entries */
+
+ /* For the address in ecx:
+ * bits 47-39 - index into pml4 table (always 0 here)
+ * bits 38-30 - index into pdp table (always 0 here)
+ * bits 29-21 - index into pd table
+ * bits 20-12 - index into page table
+ */
+
+ /* pml4e */
+
+ movl $(PDPTBASE | 3), %eax /* 3 == S/W/P */
+ movl %eax, PML4BASE
+ movl %edx, (PML4BASE + 4)
+
+ /* pdpe */
+
+ movl $(PDBASE | 3), %eax /* 3 == S/W/P */
+ movl %eax, PDPTBASE
+ movl %edx, (PDPTBASE + 4)
+
+PageLoop:
+ /* pde */
+
+ /* ebp is the byte index into the pd table */
+ movl %ecx, %ebp
+ shrl $(21 - 3), %ebp
+ andl $(0x1ff << 3), %ebp
+ addl $PDBASE, %ebp
+
+ movl $(PTBASE | 3), %eax
+ movl %eax, (%ebp)
+ movl %edx, 4(%ebp)
+
+ /* pte */
+
+ /* ebp is the byte index into the page table */
+ movl %ecx, %ebp
+ shrl $(12 - 3), %ebp
+ andl $(0x1ff << 3), %ebp
+ addl $PTBASE, %ebp
+
+ /* pages here are identity mapped */
+ movl %ecx, %eax
+ andl $0xfffff000, %eax
+ orl $3, %eax
+ movl %eax, (%ebp)
+ movl %edx, 4(%ebp)
+
+
+ /* increment to next page */
+ addl $4096, %ecx
+ cmpl e820_map + 8, %ecx
+ jb PageLoop
+
+ ret
+
+
+ /*
+ * FindMPConfig --
+ *
+ * Search various locations for the MP floating pointer structure.
+ *
+ * During later ACPI initialization, if an MADT is found, that
+ * information overrides what is found here.
+ */
+
+FindMPConfig:
+ /* According to MP spec, the places to look are:
+ *
+ * - First kB of EBDA (address can be found at 40:0e)
+ * - Last kB of system base memory (basemem top in CMOS)
+ * - In BIOS ro space between e0000 and fffff.
+ */
+
+ /* EBDA */
+ xorl %ecx, %ecx
+ movw 0x40e, %cx /* segment of EBDA */
+ testl %ecx, %ecx
+ jz NoEBDA
+ shll $4, %ecx
+ movl (%ecx), %eax
+ testw %ax, %ax /* ax = number of kB in EBDA */
+ jz NoEBDA
+
+ movl %ecx, %edx
+ addl $1024, %edx
+
+ call FindMPFP
+ testl %eax, %eax
+ jnz StoreMPFPtr
+
+ /* Last kB of system base memory */
+NoEBDA:
+ call GetBaseMemCMOS
+ /*
+ * VMW BIOS differs in mem amount between CMOS and BDA - use CMOS
+ * here, even though the value in the BDA is correct and the value
+ * in CMOS RAM is not. The reasoning is that on VMW, the MP
+ * structure isn't located there anyways, Linux uses the
+ * value from the CMOS as well, and it seems to work, and the the
+ * ACPI tables will very probably be used instead, so it's not too
+ * big an issue.
+ *
+ * XXX: Need to check how real hardware behaves and adjust
+ * accordingly (and file a PR if appropriate).
+ */
+ #xorl %edx, %edx
+ #movw 0x413, %dx
+ #shll $10, %edx
+ movl %edx, %ecx
+ subl $1024, %ecx
+ call FindMPFP
+ testl %eax, %eax
+ jnz StoreMPFPtr
+
+ /* Linux also searches the first kB of memory - try that, too */
+ xorl %ecx, %ecx
+ movl $1024, %edx
+ call FindMPFP
+ testl %eax, %eax
+ jnz StoreMPFPtr
+
+ /* BIOS ro space */
+
+ movl $0xe0000, %ecx
+ movl $0x100000, %edx
+ call FindMPFP
+ testl %eax, %eax
+ jnz StoreMPFPtr
+
+ /* MP block not found */
+NoBIOS: xorl %eax, %eax
+StoreMPFPtr:
+ movl %eax, MPFloatingPointer
+ ret
+
+
+GetBaseMemCMOS:
+ /* bytes 15h | 16h << 8 */
+ xorl %eax, %eax
+ movb $0x16, %al
+ outb %al, $0x70
+ inb $0x71, %al
+ shll $8, %eax
+
+ movb $0x15, %al
+ outb %al, $0x70
+ inb $0x71, %al
+
+ shll $10, %eax
+ movl %eax, %edx
+ ret
+
+ /*
+ * FindMPFP --
+ *
+ * Look through the address range ecx-edx to find the MP
+ * table. If it is found, return its address in eax,
+ * otherwise return 0 in eax.
+ *
+ */
+
+FindMPFP:
+ xorl %eax, %eax
+ movl $MP_MAGIC, %ebx
+1: cmpl %ebx, (%ecx)
+ jne 2f
+
+ /* have a match */
+ movl %ecx, %eax
+ ret
+
+2: addl $16, %ecx
+ cmpl %edx, %ecx
+ jb 1b
+
+ /* no match */
+ ret
+
+
+ /*
+ * Check64_OK --
+ *
+ * Check if the processor supports long mode. Return with
+ * carry clear if it does not, carry set otherwise.
+ */
+Check64_OK:
+ /* check number of extended functions */
+ movl $0x80000000, %eax
+ cpuid
+ cmpl $0x80000000, %eax
+ ja 1f
+
+ clc
+ ret
+
+1: movl $0x80000001, %eax
+ cpuid
+ bt $29, %edx
+ ret
+
+
+ /****** long mode code ******/
+
+ .code64
+ .global IntoLongMode
+IntoLongMode:
+ xorq %rbp, %rbp /* will be using frame pointer now */
+
+ call MapMemory
+
+ /* Fill in the TSS now that stacks can be allocated. */
+ call PopulateTSS
+ movl $TS, %eax
+ ltr %ax
+
+ call UnmaskNMI
+ sti
+
+ call AllocInit
+ call VideoInit
+
+ call CPUFeatures
+ call MapPCI
+ //call InitACPI
+ call InitAPIC
+
+ /* Start devices */
+ call StartPIT
+ call StartClock
+ call KeyboardInit
+ call MouseInit
+
+ call CursorInit /* have to wait for mouse irq installation */
+
+ /* say hello */
+ movq $0xff000000, %rdi
+ xorl %esi, %esi
+ addl $4, %esi
+ movl %esi, %edx
+ movl $HelloMessage, %ecx
+ call PrintMessage
+
+# call ForthInit
+
+ .global here
+here: nop
+1: hlt
+ jmp 1b
+
+
+ /*
+ * MaskNMI --
+ * UnmaskNMI --
+ *
+ * Mask/unmask NMI using external hardware.
+ *
+ */
+
+MaskNMI:
+ inb $0x70, %al
+ andb $0x7f, %al
+ outb %al, $0x70
+ inb $0x71, %al
+ ret
+
+UnmaskNMI:
+ inb $0x70, %al
+ orb $0x80, %al
+ outb %al, $0x70
+ inb $0x71, %al
+ ret
+
+
+ /*
+ * PopulateTSS --
+ *
+ * Populate the task state segment with entries for the three
+ * IDT-related stacks and with the entries for the IO bitmask.
+ */
+
+ .global PopulateTSS
+PopulateTSS:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ /* First zero all bytes */
+ movl $tss_start, %edi
+ movl $(tss_end - tss_start), %esi
+ call bzero
+
+ /* Set IO bitmask to all 1s (for now) */
+
+ movb $-1, %al
+ movsbq %al, %rax
+ movq %rax, tss_iomap(%rip)
+ movq %rax, tss_iomap+8(%rip)
+ movq %rax, tss_iomap+16(%rip)
+ movq %rax, tss_iomap+24(%rip)
+ movb %al, tss_end - 1
+
+ /* IO map */
+ movl $(tss_iomap - tss_start), %eax
+ movw %ax, tss_iomap_base
+
+ /*
+ * Allocate stacks for the ISTs.
+ *
+ * The order here needs to be from low address to high address
+ * (IRQ => CRITICAL => FAULT). This takes advantage of the
+ * adjacency of the stacks' virtual addresses and should save
+ * a few bytes.
+ */
+
+ movq $IRQ_STACK_BOTTOM, %rbx
+ leaq (IRQ_STACK_TOP - IRQ_STACK_BOTTOM)(%rbx), %rdi
+ call TSSStackAlloc
+ movq %rbx, tss_ist1 /* top of IRQ stack */
+
+ leaq (CRITICAL_STACK_TOP - CRITICAL_STACK_BOTTOM)(%rbx), %rdi
+ call TSSStackAlloc
+ movq %rbx, tss_ist2 /* top of critical stack */
+
+ leaq (FAULT_STACK_TOP - FAULT_STACK_BOTTOM)(%rbx), %rdi
+ call TSSStackAlloc
+ movq %rbx, tss_ist3 /* top of fault stack */
+
+ leave
+ ret
+
+
+ /*
+ * TSSStackAlloc --
+ *
+ * Stack allocation subroutine.
+ *
+ * Call with %rbx = bottom, %rdi = top.
+ * Return with %rax = %rbx = top
+ */
+
+TSSStackAlloc:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ /* %rbx should be the limit and %rdi the base. */
+ xchgq %rbx, %rdi
+
+1: movq $0x8000000000000002, %rsi /* NX|RW */
+ call PageAlloc
+ leaq PAGE_SIZE(%rax), %rdi
+ cmpq %rbx, %rax
+ jne 1b
+
+ leave
+ ret
+
+
+ /*
+ * CPUFeatures --
+ *
+ * Determine CPU features and install pointer to vendor-specific
+ * TestCPUFeature routine.
+ *
+ * XXX: should use alloc() insteald of PageAlloc()
+ */
+CPUFeatures:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ /* alloc a kernel page for this info */
+ movq $MM_VA_KERNEL_HEAP, %rdi
+ movq $2, %rsi /* RW */
+ call PageAlloc
+ movq %rax, %r9 /* %r9 is base of structure */
+ leaq 24(%rax), %r10 /* %r10 is index into feature array */
+ movq %rax, CPUIDInfo
+
+ /* data structure is:
+ *
+ * struct {
+ * uint64 nStandard;
+ * uint64 nHypervisor;
+ * uint64 nExtended;
+ * struct {
+ * UReg eax;
+ * UReg ebx;
+ * UReg ecx;
+ * UReg edx;
+ * } features[];
+ * };
+ */
+
+ xorl %eax, %eax /* function 0 */
+ call DoCPUID
+ addq $8, %r9 /* point to next (hv) count */
+ movq $0, (%r9) /* zero hv count */
+
+ /* Bit 31 of %ecx of CPUID leaf 0x1 is the hypervisor present bit. */
+ btl $31, (16 + 16 + 8)(%r9)
+ jnc 1f /* no hypervisor present */
+
+ movl $0x40000000, %eax
+ call DoCPUID
+
+1: addq $8, %r9
+ movl $0x80000000, %eax
+ call DoCPUID
+
+ leave
+ ret
+
+ /*
+ * DoCPUID --
+ *
+ * Loop over base, hypervisor, or extended CPUID functions.
+ *
+ * Call with %r9 pointing to count entry, %r10 pointing to
+ * cpuid array.
+ *
+ * Adjusts %r10, uses %rax, %rbx, %rcx, %rdx, %r11, and %r12.
+ *
+ */
+DoCPUID:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ /* %r9 points to count, %r10 is current cpuid entry, %r11 is
+ * limit, %r12 is current function.
+ */
+ movq %rax, %r12
+
+ cpuid
+ movq %rax, %r11 /* Store max function */
+ movq %rax, (%r9)
+ incq (%r9)
+ movb $0, 3(%r9) /* zero out high byte (0, 4, 8) */
+
+1: cmpq %r11, %r12
+ ja 1f
+
+ movl %eax, (%r10)
+ movl %ebx, 4(%r10)
+ movl %ecx, 8(%r10)
+ movl %edx, 12(%r10)
+
+ addq $16, %r10
+
+ incq %r12
+ movq %r12, %rax
+ cpuid
+ jmp 1b
+
+1: leave
+ ret
+
+
+ /****** Data ******/
+
+ .section .data
+ .align 1
+bad_e820:
+ .asciz "E820 memory map failed!"
+HelloMessage:
+ .asciz "Welcome to Marmot!"
+
+
+ .align 8
+ /* tval and tval2 are generic data holders for vprobe GUEST:test */
+ .global tval
+tval: .quad 0
+ .global tval2
+tval2: .quad 0
+
+
+GDTStart:
+ .quad 0
+ .quad 0x00df9a000000ffff /* CS32 */
+ .quad 0x00af9a000000ffff /* CS64 */
+ .quad 0x00cf92000000ffff /* DS */
+ .quad 0x008089007f000089 /* TS descriptor */
+ .quad 0x0000000000000000 /* TS continued */
+ .quad 0x0000000000000000 /* PRIV CS */
+ .quad 0x0000000000000000 /* PRIV DS */
+ .quad 0x0000000000000000 /* USER CS */
+ .quad 0x0000000000000000 /* USER DS */
+GDTEnd:
+
+
+IDTJumpTable:
+ .long DE64
+ .long DB64
+ .long NMI64
+ .long BP64
+ .long OF64
+ .long BR64
+ .long UD64
+ .long NM64
+ .long DF64
+ .long 0
+ .long TS64
+ .long NP64
+ .long SS64
+ .long GP64
+ .long PF64
+ .long 0
+ .long MF64
+ .long AC64
+ .long MC64
+ .long XF64
+
+
+ .section .bss
+
+ .align 8
+ .global frameBuffer
+frameBuffer:
+ .quad 0
+ .global frameBufferSize
+frameBufferSize:
+ .quad 0
+
+ .global e820_entries
+e820_entries:
+ .quad 0
+
+ .align 4
+ .word 0
+ .align 2
+DTSize:
+ .word 0
+DTLocation:
+ .long 0
+
+ .align 16
+ .global e820_map
+e820_map:
+ .fill (20 * MAX_E820), 1, 0
+
+ .align 4
+ .global MPFloatingPointer
+MPFloatingPointer:
+ .long 0
+
+ .section .tss
+
+ .align 1
+
+ .global tss_start
+tss_start:
+ .long 0
+
+ .global tss_rsp0
+tss_rsp0:
+ .quad 0
+ .global tss_rsp1
+tss_rsp1:
+ .quad 0
+ .global tss_rsp2
+tss_rsp2:
+ .quad 0
+
+ .quad 0
+
+ .global tss_ist1
+tss_ist1:
+ .quad 0
+ .global tss_ist2
+tss_ist2:
+ .quad 0
+ .global tss_ist3
+tss_ist3:
+ .quad 0
+ .global tss_ist4
+tss_ist4:
+ .quad 0
+ .global tss_ist5
+tss_ist5:
+ .quad 0
+ .global tss_ist6
+tss_ist6:
+ .quad 0
+ .global tss_ist7
+tss_ist7:
+ .quad 0
+
+ .quad 0
+
+ .word 0
+ .global tss_iomap_base
+tss_iomap_base:
+ .word 0
+
+ .global tss_iomap
+tss_iomap:
+ .quad 0 /* ports 0 - 63 */
+ .quad 0 /* ports 64 - 127 */
+ .quad 0 /* ports 128 - 191 */
+ .quad 0 /* ports 192 - 255 */
+
+ .byte 0 /* 0xff */
+ .global tss_end
+tss_end:
diff --git a/Marmot/marmot.bmp b/Marmot/marmot.bmp
new file mode 100644
index 0000000..28b6636
--- /dev/null
+++ b/Marmot/marmot.bmp
Binary files differ
diff --git a/Marmot/marmot.h b/Marmot/marmot.h
new file mode 100644
index 0000000..e6d9bf6
--- /dev/null
+++ b/Marmot/marmot.h
@@ -0,0 +1,366 @@
+/*
+ * marmot.h --
+ *
+ * Marmot definitions.
+ */
+
+#ifndef _MARMOT_H
+#define _MARMOT_H
+
+#include <types.h>
+#ifndef ASM
+#include <cpu.h>
+#endif
+
+/*
+ * Used for the scheduler. Timekeeping is controlled by the RTC
+ * (until high precision timing is needed).
+ */
+
+#define TICK_Hz 64
+
+
+/*
+ * e820 memory map space is statically allocated in .bss. 64 entries
+ * *should* be enough.
+ */
+
+#define MAX_E820 64
+
+/* "SMAP" */
+#define SMAP 0x534d4150
+
+/* "_MP_" */
+#define MP_MAGIC 0x5f504d5f
+
+
+/*
+ * Memmap for init code:
+ *
+ * 0 - 0x0fff BIOS data area
+ * 0x1000 - 0x1f00 IDT (240 entries)
+ * 0x1f00 - 0x2000 GDT (16 entries)
+ * 0x2000 - 0x3000 Page map level 4
+ * 0x3000 - 0x4000 Page directory pointer table
+ * 0x4000 - 0x5000 Page directory
+ * 0x5000 - 0x6000 Page table
+ * 0x5800 - 0x6000 Stack (real mode)
+ * 0x6000 - 0x7f00 bss
+ * 0x7f00 - 0x8000 TSS (0x68 + 8 bytes == rounded up 0x100)
+ * 0x7000 - 0x8000 Boot code
+ * 0x8000 - 0x10000 Loader
+ * 0x10000 - 0x18000 Stack (protected/long mode)
+ *
+ */
+
+#define IDT 0x1000
+#define GDT 0x1f00
+#define TSS 0x7f00
+
+#define PML4BASE 0x2000
+#define PDPTBASE 0x3000
+#define PDBASE 0x4000
+#define PTBASE 0x5000
+#define PAGETOP 0x6000
+
+#define STACKTOP 0x18000
+
+/*
+ * Descriptors.
+ */
+
+#define CS32 0x0008
+#define CS64 0x0010
+#define DS 0x0018
+#define TS 0x0020
+#define CSPRIV 0x0032
+#define DSPRIV 0x003a
+#define CSUSER 0x0043
+#define DSUSER 0x004b
+
+
+/*
+ * System virtual memory layout.
+ */
+
+/* Loader uses identity mapped pages. */
+#define MM_VA_LOADER_START 0
+
+/* Kernel gets from 4GB to PRIV_START */
+#define MM_VA_KERNEL_START 0x0000000100000000
+
+/* Privileged processes get from 64GB to USER_START */
+#define MM_VA_PRIV_START 0x0000001000000000
+
+/* User gets the rest. */
+#define MM_VA_USER_START 0x0000100000000000
+
+/* Top of canonical address space */
+#define MM_VA_CANONICAL_TOP 0x0000800000000000
+
+
+/*
+ * Magic values for PageAlloc and GetFreePA.
+ */
+
+#define MM_VA_DONT_CARE (-1ULL)
+#define MM_VA_INVALID (-2ULL)
+#define MM_VA_IDENT (-3ULL)
+#define MM_PA_INVALID (-4ULL)
+#define MM_VA_HEAP (-5ULL)
+
+#define MM_RW (1 << 1)
+#define MM_NX (1 << 63)
+
+/*
+ * Physmem pools used by GetFreePA.
+ */
+
+#define POOL_IDENT 0
+#define POOL_KERNEL 1
+#define POOL_PRIVILEGED 2
+#define POOL_USER 3
+
+
+#define NULL 0
+
+#define PAGE_SIZE 4096
+
+
+/*
+ * Various kernel-level stacks. All are allocated just below the top
+ * of kernel memory.
+ *
+ * FAULT_STACK - 2 page stack used by normal fault handlers
+ * CRITICAL_STACK - 4 page stack for #MC, #DF and #NMI.
+ * IRQ_STACK - 2 page stack for all IRQs
+ * KERNEL_STACK - Regular kernel stack. Grows as needed.
+ */
+
+#define FAULT_STACK_TOP MM_VA_PRIV_START
+#define FAULT_STACK_BOTTOM (FAULT_STACK_TOP - 2 * PAGE_SIZE)
+
+#define CRITICAL_STACK_TOP FAULT_STACK_BOTTOM
+#define CRITICAL_STACK_BOTTOM (CRITICAL_STACK_TOP - 4 * PAGE_SIZE)
+
+#define IRQ_STACK_TOP CRITICAL_STACK_BOTTOM
+#define IRQ_STACK_BOTTOM (IRQ_STACK_TOP - 2 * PAGE_SIZE)
+
+#define KERNEL_STACK_TOP IRQ_STACK_BOTTOM
+
+
+/* #define KERNEL_TEXT_START 0x0000000100000000 */
+/* #define KERNEL_DATA_START 0x0000000100000000 */
+/* #define KERNEL_BSS_START 0x0000000100000000 */
+#define KERNEL_HEAP_START 0x0000000800000000
+#define MM_VA_KERNEL_HEAP KERNEL_HEAP_START
+#define PRIV_HEAP_START 0x0000008000000000
+#define MM_VA_PRIV_HEAP PRIV_HEAP_START
+#define USER_HEAP_START 0x0000800000000000
+#define MM_VA_USER_HEAP USER_HEAP_START
+
+
+/* MSRs */
+
+/* aka IA32_TIME_STAMP_COUNTER */
+#define TSC_MSR 0x10
+
+/* aka IA32_APIC_BASE */
+#define APIC_BASE_MSR 0x1b
+
+/* aka IA32_EFER */
+#define EFER 0xc0000080
+
+/* syscall enable (r/w) */
+#define EFER_SCE 0
+
+/* long mode enable (r/w) */
+#define EFER_LME 8
+
+/* long mode active (r) */
+#define EFER_LMA 10
+
+/* execute disable bit enable (r/w) */
+#define EFER_NXE 11
+
+
+/*
+ * IRQ vectors. These are the same in both PIC/APIC mode.
+ */
+
+#define IRQBASE 0x20
+#define PIT_IRQ 0x20
+#define KBD_IRQ 0x21
+#define SERIAL1_IRQ 0x23
+#define SERIAL0_IRQ 0x24
+#define FDD_IRQ 0x26
+#define PIO_IRQ 0x27
+#define RTC_IRQ 0x28
+#define MOUSE_IRQ 0x2c
+
+
+#define MOUSE_SAMPLE_RATE 100
+
+
+/*
+ * RGBA color values.
+ */
+
+#define COLOR_INVALID 0x00ffffff
+
+#define COLOR_BLACK 0xff000000
+#define COLOR_WHITE 0xffffffff
+#define COLOR_RED 0xffff0000
+#define COLOR_GREEN 0xff00ff00
+#define COLOR_BLUE 0xff0000ff
+#define COLOR_PLEASING_GREEN 0xff73dba2
+#define COLOR_PURPLE 0xffff00ff
+#define COLOR_ROBINs_PURPLE 0xff8800ff
+
+#define BOOT_BACKGROUND_COLOR COLOR_PLEASING_GREEN
+
+
+#ifndef ASM
+
+typedef struct {
+ uint64 errorCode;
+ uint64 rip;
+ uint64 cs;
+ uint64 rflags;
+ uint64 rsp;
+ uint64 ss;
+} __attribute__((packed)) ExcFrame;
+
+
+/* global vprobe point for GUEST:test */
+extern volatile uint64 tval, tval2;
+#define TEST_VPROBE(v1,v2) do { tval = (v1); tval2 = (v2); \
+ asm("sfence\n.global test\ntest:\n"); \
+ } while (0)
+
+
+#define BUG_ASSERT 0
+#define BUG_UNIMPLEMENTED 1
+#define BUG_MISC 2
+
+#define ASSERT(c) if (!(c)) { Bug(BUG_ASSERT, #c, __FILE__, __LINE__); }
+#define UNIMPLEMENTED(what) Bug(BUG_UNIMPLEMENTED, what, __FILE__, __LINE__)
+void Bug(uint64, char *, char *, uint64);
+
+static inline void
+cli(void)
+{
+ __asm__ __volatile__("cli");
+}
+
+static inline void
+sti(void)
+{
+ __asm__ __volatile__("sti");
+}
+
+static inline void
+outb(uint8 val, uint16 port)
+{
+ __asm__ __volatile__("outb %b0, %w1" : : "a" (val), "Nd" (port));
+}
+
+static inline uint8
+inb(uint16 port)
+{
+ uint8 val;
+
+ __asm__ __volatile__("inb %w1, %0" : "=a" (val) : "Nd" (port));
+ return val;
+}
+
+static inline void
+outl(uint32 val, uint16 port)
+{
+ __asm__ __volatile__("outl %0, %w1" : : "a" (val), "Nd" (port));
+}
+
+static inline uint32
+inl(uint16 port)
+{
+ uint32 val;
+
+ __asm__ __volatile__("inl %w1, %0" : "=a" (val) : "Nd" (port));
+ return val;
+}
+
+
+
+#define invlpg(m) __asm__ __volatile__("invlpg (%0)":: "r" (m) : "memory");
+#define rdmsr(msr,val) do { uint32 _a, _d; \
+ __asm__ __volatile__("rdmsr" \
+ : "=a" (_a), "=d" (_d) \
+ : "c" (msr)); \
+ val = (uint64)_a | ((uint64)_d << 32);\
+ } while (0)
+#define wrmsr(msr,val) do { uint32 _a, _d; \
+ _a = (uint32)val; \
+ _d = (uint32)(val >> 32); \
+ __asm__ __volatile__("wrmsr" \
+ : \
+ : "c" (msr), "a" (_a), "d" (_d)); \
+ } while(0)
+
+
+#define __init __attribute__((section(".loader")))
+
+extern uint16 xResolution;
+extern uint16 yResolution;
+
+typedef uint64 CbID;
+typedef void (*MouseCBFun)(uint8 *, uint64);
+
+struct MouseCB {
+ struct MouseCB *next;
+ CbID id;
+ MouseCBFun cb;
+};
+
+CbID InstallMouseCB(MouseCBFun cb);
+void RemoveMouseCB(CbID id);
+
+
+void bzero(void *s, uint64 n);
+void bcopy(void *s, void *d, uint64 n);
+void bfill(void *s, uint64 n, uint8 val);
+
+uint64 strlen(char *s);
+
+void *alloc(size_t amt);
+void free(void *mem);
+
+VA RegionAlloc(VA desired, uint64 nPages, uint64 flags);
+VA PageAlloc(VA desired, uint64 flags);
+void MapIORegion(PA start, PA end, char *name);
+
+
+void TaskSchedule(uint64);
+
+
+void SetPixel(Color color, Point p);
+void PrintMessage(Color color, Point where, char *msg);
+void ColorRectangle(Color color, Point c0, Point c1);
+void ColorTriangle(Color color, Point c0, Point c1, Point c2);
+void ColorCircle(Color color, Point center, Length radius);
+
+
+void MaskPIC(uint8 irq);
+void UnmaskPIC(uint8 irq);
+
+
+/*
+ * Stub routines in interrupt.S
+ */
+
+void _IRQStub_PIT(void);
+void _IRQStub_KBD(void);
+void _IRQStub_RTC(void);
+void _IRQStub_MOUSE(void);
+
+#endif /* !ASM */
+#endif
diff --git a/Marmot/marmot_os.xcf.bz2 b/Marmot/marmot_os.xcf.bz2
new file mode 100644
index 0000000..b629722
--- /dev/null
+++ b/Marmot/marmot_os.xcf.bz2
Binary files differ
diff --git a/Marmot/mksym.pl b/Marmot/mksym.pl
new file mode 100644
index 0000000..4e598d8
--- /dev/null
+++ b/Marmot/mksym.pl
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+#
+# Parse link map and generate symbols.txt to use with VProbes.
+
+use strict;
+use warnings;
+
+my $map = 'link.map';
+die "Missing map file\n" unless -f $map;
+open MAP, "<$map" or die "Unable to open $map: $!";
+
+my %syms = ();
+
+while (my $line = <MAP>) {
+ if ($line =~ m/^\s+0x([0-9a-f]+)\s+(\w+)\s*$/) {
+ $syms{$1} = $2;
+# print "$1 T $2\n";
+ }
+}
+
+close MAP;
+
+open SYMS, ">symbols.txt" or die "Unable to open symbols.txt: $!";
+
+foreach my $addr (sort(keys(%syms))) {
+ my $sym = $syms{$addr};
+ print SYMS "$addr T $sym\n";
+}
+
+close SYMS;
diff --git a/Marmot/mm.c b/Marmot/mm.c
new file mode 100644
index 0000000..24733e3
--- /dev/null
+++ b/Marmot/mm.c
@@ -0,0 +1,1064 @@
+/*
+ * mm.c --
+ *
+ * Base memory management functions.
+ *
+ */
+
+/* XXX: this file's a mess */
+
+#include <marmot.h>
+
+
+#define PHYSMEM_BITMAP_BASE (STACKTOP)
+
+#define MAX_E820 64
+#define E820_RAM 1
+#define E820_RSVD 2
+#define E820_ACPI_DATA 3
+#define E820_ACPI_NVS 4
+
+
+typedef enum {
+ MEMTYPE_RAM,
+ MEMTYPE_ROM,
+ MEMTYPE_ACPI_DATA,
+ MEMTYPE_ACPI_NVS,
+ MEMTYPE_IO,
+ MEMTYPE_HOLE
+} MemRegionType;
+
+struct e820 {
+ uint64 base;
+ uint64 length;
+ uint32 type;
+} __attribute__((packed));
+
+extern struct e820 e820_map[MAX_E820];
+extern uint64 e820_entries;
+
+typedef uint64 PML4E;
+typedef uint64 PDPE;
+typedef uint64 PDE;
+typedef uint64 PTE;
+
+
+#define PAGE_ADDR_MASK 0x000ffffffffff000
+
+#define PML4E_ADDR_MASK 0x000ffffffffff000
+#define PML4E_NX (1 << 63)
+#define PML4E_A (1 << 5)
+#define PML4E_PCD (1 << 4)
+#define PML4E_PWT (1 << 3)
+#define PML4E_US (1 << 2)
+#define PML4E_RW (1 << 1)
+#define PML4E_P (1 << 0)
+
+#define PDPE_ADDR_MASK 0x000ffffffffff000
+#define PDPE_NX (1 << 63)
+#define PDPE_A (1 << 5)
+#define PDPE_PCD (1 << 4)
+#define PDPE_PWT (1 << 3)
+#define PDPE_US (1 << 2)
+#define PDPE_RW (1 << 1)
+#define PDPE_P (1 << 0)
+
+#define PDE_ADDR_MASK 0x000ffffffffff000
+#define PDE_NX (1 << 63)
+#define PDE_A (1 << 5)
+#define PDE_PCD (1 << 4)
+#define PDE_PWT (1 << 3)
+#define PDE_US (1 << 2)
+#define PDE_RW (1 << 1)
+#define PDE_P (1 << 0)
+
+#define PTE_ADDR_MASK 0x000ffffffffff000
+#define PTE_NX (1 << 63)
+#define PTE_G (1 << 8)
+#define PTE_PAT (1 << 7)
+#define PTE_D (1 << 6)
+#define PTE_A (1 << 5)
+#define PTE_PCD (1 << 4)
+#define PTE_PWT (1 << 3)
+#define PTE_US (1 << 2)
+#define PTE_RW (1 << 1)
+#define PTE_P (1 << 0)
+
+
+#define PTE_ENTRIES (PAGE_SIZE / sizeof(PTE))
+
+
+#define PTOFFSET(va) (((va) >> 12) & 0x1ff)
+
+#define MKPML4E(pdp, flags) (((pdp) & PML4E_ADDR_MASK) | flags)
+#define MKPDPE(pd, flags) (((pd) & PDPE_ADDR_MASK) | flags)
+#define MKPDE(pt, flags) (((pt) & PDE_ADDR_MASK) | flags)
+#define MKPTE(pa, flags) (((pa) & PTE_ADDR_MASK) | flags)
+
+
+/*
+ * Use the AVL bits (11-9) in each PTE to mark a page as used or free.
+ */
+
+#define MM_STATUS_MASK 0x0000000000000e00
+#define MM_PAGE_USED 0x200
+#define MM_PAGE_INVALID 0x400
+
+#define CANONICAL_MASK 0x00007fffffffffff
+
+
+#define BITMAP_SIZE(count) (count >> 3)
+
+typedef uint8 MemoryPool;
+
+typedef struct {
+ PA base;
+ PA limit;
+ MemRegionType type;
+} MemRegion;
+
+
+#define MEMORY_REGIONS_MAX 64
+
+static MemRegion memoryRegions[MEMORY_REGIONS_MAX];
+static uint64 memoryRegionCount;
+
+typedef struct {
+ char *name;
+ PA base;
+ PA limit;
+ uint64 count;
+ uint8 *map;
+} Pool;
+
+Pool pools[4];
+
+static char *poolNames[] = {
+ "ident",
+ "kernel",
+ "priv",
+ "user"
+};
+
+
+
+MemRegionType __init
+GetMemType(PA addr)
+{
+ uint64 r;
+
+ for (r = 0; r < memoryRegionCount; r++) {
+ if (addr >= memoryRegions[r].base && addr < memoryRegions[r].limit) {
+ return memoryRegions[r].type;
+ }
+ }
+
+ return MEMTYPE_HOLE;
+}
+
+
+void __init
+AddMemoryRegion(PA base, PA limit, MemRegionType type)
+{
+ if (memoryRegionCount == MEMORY_REGIONS_MAX) {
+ // PANIC();
+ }
+
+ memoryRegions[memoryRegionCount].base = base;
+ memoryRegions[memoryRegionCount].limit = limit;
+ memoryRegions[memoryRegionCount].type = type;
+
+ memoryRegionCount++;
+}
+
+
+/*
+ * FixupE820 --
+ *
+ * Sort through the e820 entries, ensuring they're in order, and
+ * joining adjacent identical entries. Then add the regions to
+ * the region map.
+ *
+ */
+
+void __init
+FixupE820(void)
+{
+ uint64 d, j, k;
+ int doneSorting;
+
+ if (e820_entries < 2) {
+ return;
+ }
+
+ /* sort the entries */
+ doneSorting = 0;
+ while (!doneSorting) {
+ doneSorting = 1;
+
+ for (k = 0; k < e820_entries - 1; k++) {
+ if (e820_map[k].base > e820_map[k + 1].base) {
+ struct e820 tmp;
+
+ tmp.base = e820_map[k].base;
+ tmp.length = e820_map[k].length;
+ tmp.type = e820_map[k].type;
+
+ e820_map[k].base = e820_map[k + 1].base;
+ e820_map[k].length = e820_map[k + 1].length;
+ e820_map[k].type = e820_map[k + 1].type;
+
+ e820_map[k].base = tmp.base;
+ e820_map[k].length = tmp.length;
+ e820_map[k].type = tmp.type;
+
+ doneSorting = 0;
+ }
+ }
+ }
+
+ /* merge adjacent entries */
+ k = 0;
+ j = 1;
+ while (k < e820_entries - 1) {
+ if (((e820_map[k].base + e820_map[k].length) >= e820_map[j].base) &&
+ (e820_map[k].type == e820_map[j].type)) {
+
+ /* merge j into k */
+ if (e820_map[k].base + e820_map[k].length <
+ e820_map[j].base + e820_map[j].length) {
+ /* second entry has higher limit than first */
+ e820_map[k].length = ((e820_map[j].base + e820_map[j].length) -
+ e820_map[k].base);
+ } else {
+ /* first entry entirely overlaps second - do nothing */
+ }
+
+ /* move rest of entries down */
+ for (d = k + 1; j < e820_entries; j++) {
+ e820_map[d].base = e820_map[j].base;
+ e820_map[d].length = e820_map[j].length;
+ e820_map[d].type = e820_map[j].type;
+ }
+
+ e820_entries--;
+ } else {
+ k++;
+ }
+
+ j = k + 1;
+ }
+
+ /* adjust to page boundaries */
+ for (k = 0; k < e820_entries; k++) {
+
+ if (e820_map[k].base & 0xfff) {
+ if (e820_map[k].type == E820_RAM) {
+ /* RAM - adjust base up */
+ e820_map[k].length -= e820_map[k].base & 0xfff;
+ e820_map[k].base = (e820_map[k].base & (~0xfffULL)) + 4096;
+ } else {
+ /* otherwise adjust down*/
+ e820_map[k].length += e820_map[k].base & 0xfff;
+ e820_map[k].base = e820_map[k].base & (~0xfffULL);
+ }
+ }
+
+ if (((e820_map[k].base + e820_map[k].length) & 0xfff) &&
+ e820_map[k].type == E820_RAM) {
+ /* adjust limit down */
+ e820_map[k].length -= (e820_map[k].base + e820_map[k].length) & 0xfff;
+ }
+ }
+}
+
+
+void __init
+AddE820Regions(void)
+{
+ uint64 k;
+
+ FixupE820();
+
+ for (k = 0; k < e820_entries; k++) {
+ MemRegionType t = MEMTYPE_HOLE;
+
+ switch (e820_map[k].type) {
+ case E820_RAM:
+ t = MEMTYPE_RAM;
+ break;
+ case E820_RSVD:
+ t = MEMTYPE_ROM;
+ break;
+ case E820_ACPI_DATA:
+ t = MEMTYPE_ACPI_DATA;
+ break;
+ case E820_ACPI_NVS:
+ t = MEMTYPE_ACPI_NVS;
+ break;
+ }
+
+ AddMemoryRegion((PA)e820_map[k].base,
+ (PA)(e820_map[k].base + e820_map[k].length),
+ t);
+ }
+}
+
+
+extern uint64 GetCR3(void);
+asm(".global GetCR3\n"
+ "GetCR3:\n"
+ "\tmovq %cr3, %rax\n"
+ "\tret\n");
+extern uint64 GetCR2(void);
+asm(".global GetCR2\n"
+ "GetCR2:\n"
+ "\tmovq %cr2, %rax\n"
+ "\tret\n");
+extern void SetCR3(uint64);
+asm(".global SetCR3\n"
+ "SetCR3:\n"
+ "\tmovq %rdi, %cr3\n"
+ "\tret\n");
+extern void SetCR2(uint64);
+asm(".global SetCR2\n"
+ "SetCR2:\n"
+ "\tmovq %rdi, %cr2\n"
+ "\tret\n");
+extern void FlushCR3(void);
+asm(".global FlushCR3\n"
+ "FlushCR3:\n"
+ "\tmovq %cr3, %rax\n"
+ "\tmovq %rax, %cr3\n"
+ "\tret\n");
+
+
+/* global flag that is TRUE when swapping is enabled */
+volatile Bool swapping = FALSE;
+
+// XXX: for now
+#define PAGED(e) FALSE
+
+/*
+ * WalkPT --
+ *
+ * Walk a page table for a given VA and return a pointer to the
+ * PTE. If no entry exists for the virtual address in any of the
+ * tables, the entry is created.
+ *
+ */
+
+PTE *
+WalkPT(VA addr)
+{
+ PML4E *pml4, *pml4e;
+ PDPE *pdp, *pdpe;
+ PDE *pd, *pde;
+ PTE *pt, *pte;
+
+ /* PML4 => PDP */
+
+ pml4 = (PML4E *)(GetCR3() & ~0xfffULL);
+ pml4e = &pml4[((addr >> 39) & 0x1ff)];
+
+ if (*pml4e & PML4E_P) {
+ pdp = (PDPE *)(*pml4e & PML4E_ADDR_MASK);
+ } else {
+ /* PDP is swapped out or not yet allocated. */
+
+ if (swapping && PAGED(*pdpe)) {
+ /* Swap it in. */
+
+ } else {
+ /* Allocate new PDP */
+ pdp = (PDPE *)PageAlloc(MM_VA_IDENT, 0);
+
+ bzero(pdp, PAGE_SIZE);
+ *pml4e = MKPDPE((PA)pdp, PDPE_P);
+ }
+ }
+
+ /* PDP => PD */
+
+ pdpe = &pdp[((addr >> 30) & 0x1ff)];
+
+ if (*pdpe & PDPE_P) {
+ pd = (PDE *)(*pdpe & PDPE_ADDR_MASK);
+ } else {
+ /* PD is either paged out or not yet allocated. */
+
+ if (swapping && PAGED(*pdpe)) {
+ /* Swap it in. */
+
+ } else {
+ /* Allocate new PD */
+
+ pd = (PDE *)PageAlloc(MM_VA_IDENT, 0);
+ bzero(pd, PAGE_SIZE);
+ *pdpe = MKPDPE((PA)pd, PDPE_P);
+ }
+ }
+
+
+ pde = &pd[((addr >> 21) & 0x1ff)];
+
+ if (*pde & PDE_P) {
+ pt = (PTE *)(*pde & PDE_ADDR_MASK);
+ } else {
+ if (swapping && PAGED(*pde)) {
+ /* Swap it in */
+
+ } else {
+ /* Allocate new PT */
+
+ pt = (PTE *)PageAlloc(MM_VA_IDENT, 0);
+ bzero(pt, PAGE_SIZE);
+ *pde = MKPDE((PA)pt, PDE_P);
+ }
+ }
+
+ pte = &pt[((addr >> 12) & 0x1ff)];
+
+ return pte;
+}
+
+
+
+extern uint64 GetCPL(void);
+asm(".global GetCPL\n"
+ "GetCPL:\n"
+ "\tmovl %cs, %eax\n"
+ "\tandl $3, %eax\n"
+ "\tmovzwq %ax, %rax\n" /* may not be necessary */
+ "\tret\n");
+
+/*
+ * GetFreePA --
+ *
+ * Find a free physical page from the pool and return its
+ * address. Once swapping is turned on, this function will
+ * always return a free page.
+ */
+
+PA
+GetFreePA(MemoryPool pool)
+{
+ PA freePage = MM_PA_INVALID;
+ uint64 byte, bit;
+ uint64 pageOffset = -1ULL;
+ uint64 r;
+
+ /*
+ * Find a 0 bit in the bitmask and convert it to a page offset.
+ */
+
+ for (byte = 0; byte < BITMAP_SIZE(pools[pool].count); byte++) {
+ if (pools[pool].map[byte] != 0xff) {
+
+ for (bit = 0; bit < 8; bit++) {
+ if (pools[pool].map[byte] & (1 << bit)) {
+ continue;
+ }
+
+ break;
+ }
+
+ pageOffset = byte * 8 + bit;
+ pools[pool].map[byte] |= (1 << bit);
+
+ break;
+ }
+ }
+
+ if (pageOffset == -1ULL) {
+ // XXX: do some paging instead of just shutting down
+ asm("cli; hlt");
+ }
+
+ /*
+ * Now scan through the regions, finding where this page is in memory.
+ */
+
+ for (r = 0; r < memoryRegionCount; r++) {
+ if (memoryRegions[r].type == MEMTYPE_RAM &&
+ pools[pool].base >= memoryRegions[r].base &&
+ pools[pool].base < memoryRegions[r].limit) {
+
+ if (memoryRegions[r].base + (pageOffset << 12) <
+ memoryRegions[r].limit) {
+
+ freePage = memoryRegions[r].base + (pageOffset << 12);
+ break;
+
+ } else {
+ pageOffset -= (memoryRegions[r].limit -
+ memoryRegions[r].base) >> 12;
+ }
+ }
+ }
+
+/* tval = pageOffset; tval2 = freePage; asm("\t.global test\ntest:\n"); */
+
+ return freePage;
+}
+
+void
+ReleasePA(PA addr)
+{
+ /* XXX */
+}
+
+
+void
+AdjustVPF(VA *pDesired, MemoryPool *pPool, uint64 *pFlags)
+{
+ VA desired;
+ MemoryPool pool;
+ uint64 flags;
+
+ desired = *pDesired;
+ pool = *pPool;
+ flags = *pFlags;
+
+ switch (GetCPL()) {
+ case 0:
+ pool = POOL_KERNEL;
+
+ if (desired == MM_VA_DONT_CARE) {
+ desired = MM_VA_KERNEL_START;
+ } else if (desired == MM_VA_HEAP) {
+ desired = MM_VA_KERNEL_HEAP;
+ } else if (desired == MM_VA_IDENT) {
+ desired = MM_VA_LOADER_START;
+ pool = POOL_IDENT;
+ }
+ break;
+ case 1:
+ case 2:
+ if (desired == MM_VA_DONT_CARE) {
+ desired = MM_VA_PRIV_START;
+ } else if (desired == MM_VA_HEAP) {
+ desired = MM_VA_PRIV_HEAP;
+ }
+ pool = POOL_PRIVILEGED;
+ break;
+ case 3:
+ if (desired == MM_VA_DONT_CARE) {
+ desired = MM_VA_USER_START;
+ } else if (desired == MM_VA_HEAP) {
+ desired = MM_VA_USER_HEAP;
+ }
+ desired = MM_VA_USER_START;
+ pool = POOL_USER;
+ flags |= PTE_US;
+ break;
+ }
+
+ desired &= PTE_ADDR_MASK; // align to page boundary and ensure canonicality
+
+ *pDesired = desired;
+ *pPool = pool;
+ *pFlags = flags;
+}
+
+
+/*
+ * PageAlloc --
+ *
+ * Allocate a single page of memory and a physical page to back
+ * it. If a virtual address is requested, the allocater attempts
+ * to map there. If MM_VA_DONT_CARE is passed in instead, the
+ * allocater will map at the first available address.
+ */
+
+VA
+PageAlloc(VA desired, uint64 flags)
+{
+ PA freePage;
+ PTE *pte = NULL;
+ VA va = MM_VA_INVALID;
+ MemoryPool pool = POOL_USER;
+
+ AdjustVPF(&desired, &pool, &flags);
+
+ freePage = GetFreePA(pool);
+
+ if (pool == POOL_IDENT) {
+ pte = WalkPT((VA)freePage);
+ ASSERT((*pte & MM_STATUS_MASK) == 0);
+
+ va = (VA)freePage;
+ } else {
+ VA search = desired;
+
+ /*
+ * Scan for an unused VA. If MM_VA_DONT_CARE was passed in,
+ * this may be slow...
+ */
+
+ pte = WalkPT(desired);
+
+ while (*pte & MM_STATUS_MASK) {
+ search += PAGE_SIZE;
+ pte = WalkPT(search);
+ }
+
+ va = search;
+ }
+
+ /* Update PTE to point to freePage */
+ *pte = MKPTE(freePage, flags | MM_PAGE_USED | PTE_P);
+
+ return va;
+}
+
+
+/*
+ * RegionAlloc --
+ *
+ * Allocate a contiguous region of virtual memory. Pages cannot
+ * be allocated from POOL_IDENT here.
+ *
+ * Returns NULL if a contiguous region cannot be found.
+ *
+ * This is intended to be the general-purpose memory allocater.
+ */
+
+VA
+RegionAlloc(VA desired, uint64 nPages, uint64 flags)
+{
+ MemoryPool pool = POOL_USER;
+ VA found = MM_VA_INVALID, start, scan, limit;
+ PTE *pte;
+ uint64 n;
+
+ AdjustVPF(&desired, &pool, &flags);
+
+ ASSERT(pool != POOL_IDENT);
+
+ if (desired < MM_VA_PRIV_START) {
+ limit = MM_VA_PRIV_START;
+ } else if (desired < MM_VA_USER_START) {
+ limit = MM_VA_USER_START;
+ } else {
+ limit = MM_VA_CANONICAL_TOP;
+ }
+
+ /* Need to find an nPage region in virtual space that is available. */
+
+ for (start = desired; start < limit; start += PAGE_SIZE) {
+ pte = WalkPT(start);
+
+ if (*pte & MM_STATUS_MASK) {
+ continue;
+ }
+
+ for (scan = start + PAGE_SIZE, n = 0;
+ n < nPages && scan < limit;
+ n++, scan += PAGE_SIZE) {
+
+ pte = WalkPT(scan);
+
+ if (*pte & MM_STATUS_MASK) {
+ break;
+ }
+ }
+
+ if (n == nPages) {
+ found = start;
+ break;
+ }
+ }
+
+ if (found == MM_VA_INVALID) {
+ return NULL;
+ }
+
+ for (scan = found, n = 0; n < nPages; n++, scan += PAGE_SIZE) {
+ pte = WalkPT(scan);
+ *pte = MKPTE(0, flags | MM_PAGE_USED); /* Physmem allocation is lazy. */
+ }
+
+ return found;
+}
+
+
+/*
+ * PageFree --
+ *
+ * Release a page of memory and its virtual mapping.
+ */
+
+void
+PageFree(VA page)
+{
+ PTE *pte;
+ PA physPage;
+
+ pte = WalkPT(page);
+ physPage = *pte & PTE_ADDR_MASK;
+
+ *pte = 0;
+ ReleasePA(physPage);
+}
+
+
+/*
+ * PageRemap --
+ *
+ * Remap a page's virtual address. Return TRUE if successful,
+ * and FALSE if the target VA is already in use or is outside the
+ * allowable range.
+ */
+
+Bool
+PageRemap(VA current, VA new)
+{
+
+ return FALSE;
+}
+
+
+#define PF_NP 0x01
+#define PF_RW 0x02
+#define PF_US 0x04
+#define PF_RSVD 0x08
+#define PF_ID 0x10
+
+/*
+ * HandlePF --
+ *
+ * Page fault handler (int 14). Called from stub in interrupts.S.
+ */
+
+void
+HandlePF(ExcFrame *f)
+{
+ VA CR2;
+ PA freePage;
+ PTE *pte;
+ MemoryPool pool = POOL_USER;
+
+ CR2 = GetCR2();
+ pte = WalkPT(CR2);
+
+ if (f->errorCode & PF_NP) {
+ /* #PF caused by permissions will be handled once tasks are
+ implemented. */
+ UNIMPLEMENTED("#PF");
+ }
+
+ /*
+ * #PF caused by mapped but not allocated page - allocate it here.
+ */
+
+ switch (f->cs & 0x3) {
+ case 0:
+ pool = POOL_KERNEL;
+ break;
+ case 1:
+ case 2:
+ pool = POOL_PRIVILEGED;
+ break;
+ case 3:
+ pool = POOL_USER;
+ break;
+ }
+
+ /* XXX: Once swapping is implemented, will need to switch to kernel
+ * stack and make this a deferred function call as getting a free
+ * PA may take time and require interrupts to be enabled. */
+
+ freePage = GetFreePA(pool);
+ *pte = MKPTE(freePage, (*pte & 0xfff) | PTE_P);
+
+ SetCR2(0);
+}
+
+
+/*
+ * MapFirstPT --
+ *
+ * Identity map the first page table. This is called very early
+ * in startup and is needed by the memory mapper.
+ */
+
+void __init
+MapFirstPT(void)
+{
+ PA current;
+ PTE *pt = (PTE *)PTBASE;
+
+ /*
+ * PML4/PDPT/PD are already initialized.
+ */
+
+ /* First page is BIOS data area - mark ro */
+ pt[PTOFFSET(0)] = MKPTE(0, PTE_P | MM_PAGE_INVALID);
+
+ /*
+ * Below STACKTOP (0x18000), all pages are used by the loader.
+ * Mark them as such.
+ */
+
+ for (current = PAGE_SIZE;
+ current < PTE_ENTRIES * PAGE_SIZE;
+ current += PAGE_SIZE) {
+ MemRegionType type;
+ PTE pte;
+
+ type = GetMemType(current);
+
+ if (type == MEMTYPE_RAM) {
+ pte = MKPTE(current, PTE_P|PTE_RW);
+
+ if (current < STACKTOP) {
+ pte |= MM_PAGE_USED;
+ }
+
+ } else if (type == MEMTYPE_ROM) {
+ pte = MKPTE(current, PTE_P | MM_PAGE_INVALID);
+ } else if (type == MEMTYPE_IO ||
+ type == MEMTYPE_ACPI_DATA ||
+ type == MEMTYPE_ACPI_NVS) {
+ pte = MKPTE(current, PTE_P|PTE_RW|PTE_PCD | MM_PAGE_INVALID);
+ } else {
+ pte = MKPTE(current, 0 | MM_PAGE_INVALID); /* mark page NP */
+ }
+
+ pt[PTOFFSET(current)] = pte;
+ }
+}
+
+
+/*
+ * MapIORegion --
+ *
+ * Identity map an IO region.
+ */
+
+void
+MapIORegion(PA start, PA end, char *name)
+{
+ PTE *pte;
+ VA va;
+
+ start &= PAGE_ADDR_MASK;
+ end = (PAGE_SIZE - 1 + end) & PAGE_ADDR_MASK;
+
+ for (va = start; va < end; va += PAGE_SIZE) {
+ pte = WalkPT(va);
+ *pte = MKPTE(va, MM_PAGE_INVALID|PTE_PCD|PTE_RW|PTE_P);
+ }
+}
+
+
+/*
+ * AddRegionsToPools --
+ *
+ * Go through memory regions and memory pools and assign base and
+ * limit addresses to each pool.
+ */
+
+void __init
+AddRegionsToPools(void)
+{
+ uint64 r, p, countLeft;
+ PA startAddr;
+
+ r = p = 0;
+ countLeft = pools[p].count * PAGE_SIZE;
+ pools[p].base = startAddr = memoryRegions[0].base;
+
+ while (r < memoryRegionCount && p < 4) {
+ if (memoryRegions[r].type != MEMTYPE_RAM) {
+ r++;
+ continue;
+ }
+
+ if (startAddr < memoryRegions[r].base) {
+ /* Update startAddr to the current region. */
+ startAddr = memoryRegions[r].base;
+ }
+
+ if (countLeft == 0) {
+ countLeft = pools[p].count * PAGE_SIZE;
+ pools[p].base = startAddr;
+ }
+
+ if (startAddr + countLeft <= memoryRegions[r].limit) {
+ startAddr += countLeft;
+ countLeft = 0;
+ pools[p].limit = startAddr; /* actually end address here */
+ p++;
+ } else if (startAddr + countLeft > memoryRegions[r].limit) {
+ countLeft -= memoryRegions[r].limit - startAddr;
+ r++;
+ }
+ }
+}
+
+
+static uint64 __init
+CalculateTotalMem(void)
+{
+ uint64 mem, r;
+
+ for (mem = 0, r = 0; r < memoryRegionCount; r++) {
+ if (memoryRegions[r].type == MEMTYPE_RAM) {
+ mem += memoryRegions[r].limit - memoryRegions[r].base;
+ }
+ }
+
+ return mem;
+}
+
+
+/*
+ * CreateMemPools --
+ *
+ * Divide available physical memory into pools.
+ *
+ * Initial allocations are:
+ *
+ * ident - 8MB - used for page tables and other basic data structures
+ * kernel - 8MB - kernel text/data
+ * priv - 16MB - privileged processes (drivers)
+ * user - rest - user physmem allocation
+ */
+
+#define MB (1024ULL * 1024ULL)
+#define GB (1024ULL * 1024ULL * 1024ULL)
+
+void __init
+CreateMemPools(void)
+{
+ uint64 totalMem, totalPages, bitmapPages, p;
+ PA addr;
+
+ /* the number of pages in each pool must be divisible by 8 */
+ pools[0].name = poolNames[0];
+ pools[0].count = 8 * MB / PAGE_SIZE;
+ pools[1].name = poolNames[1];
+ pools[1].count = 8 * MB / PAGE_SIZE;
+ pools[2].name = poolNames[2];
+ pools[2].count = 16 * MB / PAGE_SIZE;
+ pools[3].name = poolNames[3];
+
+ /*
+ * Each page of bitmask can represent 32768 pages (128MB). As the
+ * range 0x18000 - 0x98000 is used for bitmasks, this allows a
+ * maximum of 4194304 pages or 16GB physical memory. Should this
+ * limit become onerous, this should be pretty easy to revisit.
+ */
+
+ totalMem = CalculateTotalMem();
+
+ if (totalMem > 16 * GB) {
+ totalMem = 16 * GB;
+ }
+
+ if (totalMem < 32 * MB) {
+ // XXX: PANIC("Not enough memory");
+ asm("cli; hlt\n");
+ } else if (totalMem < 64 * MB) {
+ /* Small mem - halve pool allocations. */
+ pools[0].count = 4 * MB / PAGE_SIZE;
+ pools[1].count = 4 * MB / PAGE_SIZE;
+ pools[2].count = 8 * MB / PAGE_SIZE;
+ }
+
+ pools[3].count = (totalMem / PAGE_SIZE - pools[0].count -
+ pools[1].count - pools[2].count);
+
+ totalPages = (pools[0].count + pools[1].count +
+ pools[2].count + pools[3].count);
+
+ /* round up to next full bitmap page */
+ if (totalPages & 0x7fff) {
+ totalPages = (totalPages & 0xffffffffffff8000) + 0x8000;
+ }
+
+ bitmapPages = totalPages >> 15; /* div 32768 */
+
+ //tval = bitmapPages; asm("\t.global test\ntest:\n");
+
+ pools[0].map = (uint8 *)PHYSMEM_BITMAP_BASE;
+ pools[1].map = (uint8 *)((uint64)pools[0].map + BITMAP_SIZE(pools[0].count));
+ pools[2].map = (uint8 *)((uint64)pools[1].map + BITMAP_SIZE(pools[1].count));
+ pools[3].map = (uint8 *)((uint64)pools[2].map + BITMAP_SIZE(pools[2].count));
+
+ AddRegionsToPools();
+
+ /*
+ * Finally mark known pages as used in the ident bitmap.
+ */
+
+ /* zero out bitmaps */
+ bzero(pools[0].map, BITMAP_SIZE(pools[0].count));
+ bzero(pools[1].map, BITMAP_SIZE(pools[1].count));
+ bzero(pools[2].map, BITMAP_SIZE(pools[2].count));
+ bzero(pools[3].map, BITMAP_SIZE(pools[3].count));
+
+ /*
+ * Used pages are:
+ * 0 - 0x1000 : BDA
+ * 0x1000 - 0x6000 : GDT/IDT/PML4/PDPT/PD/PT
+ * 0x6000 - 0x8000 : loader bss (can be freed later)
+ * 0x8000 - 0x10000 : loader text/data/rodata
+ * 0x10000 - 0x18000 : stack
+ * 0x18000 - ? : bitmaps
+ */
+
+ for (addr = 0; addr < STACKTOP; addr += PAGE_SIZE) {
+ uint64 ppn, byte, bit;
+
+ ppn = addr >> 12;
+
+ byte = ppn >> 3;
+ bit = ppn & 7;
+
+ pools[0].map[byte] |= (uint8)(1 << bit);
+ }
+
+ for (p = 0; p < bitmapPages; p++) {
+ uint64 addr, ppn, byte, bit;
+
+ addr = (PA)PHYSMEM_BITMAP_BASE + p * PAGE_SIZE;
+ ppn = addr >> 12;
+
+ byte = ppn >> 3;
+ bit = ppn & 7;
+
+ pools[0].map[byte] |= (uint8)(1 << bit);
+ }
+}
+
+
+
+void __init
+MapMemory(void)
+{
+ /*
+ * Add known memory regions to list.
+ */
+
+ memoryRegionCount = 0;
+ AddE820Regions();
+
+ /*
+ * Fill in the first page table - that will provide some breathing
+ * room to set up all the various data structures. As part of
+ * this, clobber the original page tables (though since this region
+ * will be identity mapped, it won't make a difference).
+ */
+
+ MapFirstPT();
+ FlushCR3();
+
+ asm("\t.global mapped\nmapped:\n");
+
+ /* Now there's room for the rest of the page tables. */
+
+ CreateMemPools();
+}
diff --git a/Marmot/panic.c b/Marmot/panic.c
new file mode 100644
index 0000000..eb7980f
--- /dev/null
+++ b/Marmot/panic.c
@@ -0,0 +1,96 @@
+/*
+ * panic.c --
+ *
+ * Panic - print a message to the screen and bail.
+ */
+
+#include <marmot.h>
+
+static char *types[] = {
+ "Assertion failed:",
+ "Unimplemented feature:",
+ "Miscellaneous failure:"
+};
+
+
+/*
+ * formatDec --
+ *
+ * Limited decimal number formatter that only handles unsigned
+ * numbers less than 10,000,000.
+ */
+
+void
+formatDec(char s[], uint64 n)
+{
+ uint64 p, k;
+
+ if (n >= 10000000) {
+ return;
+ }
+
+ for (p = 0; n; p++) {
+ s[p] = '0' + n % 10;
+ n /= 10;
+ }
+
+ for (k = 0; k < p / 2; k++) {
+ char c;
+ c = s[k];
+ s[k] = s[p - k - 1];
+ s[p - k - 1] = c;
+ }
+}
+
+void
+Bug(uint64 type, char *cond, char *file, uint64 line)
+{
+ Point p0, p1;
+ uint64 maxStr = ((uint64)xResolution - 8) / 8;
+ char lineStr[] = {'L', 'i', 'n', 'e', ':', ' ', 0, 0, 0, 0, 0, 0, 0, 0};
+
+ /*
+ * Bug message looks like:
+ *
+ * Type message:
+ * cond
+ * file
+ * Line line
+ *
+ * Type message can be:
+ *
+ * BUG_ASSERT Assertion failed
+ * BUG_UNIMPL Unimplemented feature
+ * BUG_MISC Miscellaneous failure
+ *
+ */
+
+ p0.x = 0;
+ p0.y = 0;
+ p1.x = 1280;
+ p1.y = 4 * 16 + 5 * 4;
+ ColorRectangle(COLOR_RED, p0, p1);
+
+ p0.x = 4;
+ p0.y = 4;
+ PrintMessage(COLOR_BLACK, p0, types[type]);
+
+ p0.y += 20;
+ if (strlen(cond) > maxStr) {
+ cond[maxStr - 1] = '\0';
+ }
+ PrintMessage(COLOR_BLACK, p0, cond);
+
+ p0.y += 20;
+ if (strlen(file) > maxStr) {
+ file[maxStr - 1] = '\0';
+ }
+ PrintMessage(COLOR_BLACK, p0, file);
+
+ p0.y += 20;
+ formatDec(lineStr + 6, line);
+ PrintMessage(COLOR_BLACK, p0, lineStr);
+
+ cli();
+ asm("hlt");
+}
diff --git a/Marmot/pci.c b/Marmot/pci.c
new file mode 100644
index 0000000..aaeb470
--- /dev/null
+++ b/Marmot/pci.c
@@ -0,0 +1,343 @@
+/*
+ * pci.c --
+ *
+ * PCI device mapping and enumeration.
+ */
+
+#include <marmot.h>
+
+/*
+ * Format of a PCI address (pg 32):
+ *
+ * Bit 31: Enable bit
+ * Bits 24-30: Reserved MBZ
+ * Bits 16-23: Bus number (8?)
+ * Bits 11-15: Device number (32)
+ * Bits 8-10: Function number (8)
+ * Bits 2-7: Register number (64)
+ * Bit 1: MBZ
+ * Bit 0: MBZ
+ *
+ * PCI configuration space looks like (PCI LB2.3 pg195):
+ *
+ * 31 16 15 0
+ * | Device ID | Vendor ID |:0x00
+ * | Status | Command |:0x04
+ * | Base class | Subclass | Registers | Revision ID |:0x08
+ * | BIST | Header Type | Latency Timer | Cache Line Size |:0x0c
+ * | |:0x10
+ * | |:0x14
+ * | Base Address Registers |:0x18
+ * | |:0x1c
+ * | |:0x20
+ * | |:0x24
+ * | Cardbus CIS Pointer |:0x28
+ * | Subsystem Device ID | Subsystem Vendor ID |:0x2c
+ * | Expansion ROM base address |:0x30
+ * | Reserved | Capabilities Pointer |:0x34
+ * | Reserved |:0x38
+ * | Max_Lat | Min_Gnt | Interrupt Pin | Interrupt Line |:0x3c
+ *
+ *
+ * if bit 7 in Header Type is 1, device is multifunction.
+ */
+
+#define MKPCI(b,d,f) ((((b) & 0xff) << 16) | \
+ (((d) & 0x1f) << 11) | \
+ (((f) & 0x7) << 8))
+#define PCIBUS(bdf) (((bdf) >> 16) & 0xff)
+#define PCIDEV(bdf) (((bdf) >> 11) & 0x1f)
+#define PCIFUN(bdf) (((bdf) >> 8) & 0x7)
+
+#define PCI_ADDRESS 0xcf8
+#define PCI_DATA 0xcfc
+
+struct PCIDev {
+ struct PCIDev *next;
+
+ uint32 bdf;
+ uint16 vendor;
+ uint16 device;
+
+ uint16 command;
+ uint16 status;
+ uint8 revision;
+ uint8 baseClass;
+ uint8 subClass;
+ uint8 regInterface;
+
+ uint8 cacheLine;
+ uint8 latTimer;
+ uint8 headerType;
+ uint8 bist;
+ uint16 subsystemVendor;
+ uint16 subsystemDevice;
+
+ uint32 BAR[6];
+ uint32 size[6];
+
+ uint32 ROMbase;
+ uint8 irqPin;
+ uint8 irqLine;
+ uint16 _pad;
+} __attribute__((packed));
+
+
+volatile uint64 pciAddress; // vprobes
+volatile uint64 pciData; // vprobes
+
+struct PCIDev *pciRoot;
+
+enum PCIRW {
+ PCI_READ,
+ PCI_WRITE
+};
+
+
+uint32
+PCICfgRW(uint32 address, uint32 reg, uint32 data, enum PCIRW rw)
+{
+ if (PCIBUS(address)) {
+ address |= 1; /* type 1 address */
+ }
+
+ address |= 0x80000000 | reg;
+
+ outl(address, PCI_ADDRESS);
+
+ if (rw == PCI_READ) {
+ data = inl(PCI_DATA);
+ } else {
+ outl(data, PCI_DATA);
+ }
+
+ return data;
+}
+
+
+#define IOBAR(b) ((b) & 1)
+
+static inline Bool
+HasBAR(uint8 base)
+{
+ return !((base == 0x0) || /* legacy */
+ (base == 0x5) || /* memory controller */
+ (base == 0x6) || /* bridge */
+ (base > 0x11)); /* reserved */
+}
+
+uint32
+GetBARSize(uint32 bdf, uint32 reg)
+{
+ uint32 bar, size;
+
+ bar = PCICfgRW(bdf, reg, 0, PCI_READ);
+ PCICfgRW(bdf, reg, 0xffffffff, PCI_WRITE);
+ size = PCICfgRW(bdf, reg, 0, PCI_READ);
+ PCICfgRW(bdf, reg, bar, PCI_WRITE);
+
+ if (IOBAR(bar)) {
+ size = (~(size & ~0x1UL) + 1) & 0xffff;
+ } else {
+ size = ~(size & ~0xfUL) + 1;
+ }
+
+ return size;
+}
+
+
+void
+EnumeratePCI(void)
+{
+ uint32 bus, device, fcn, data;
+ struct PCIDev *last = NULL;
+
+ for (bus = 0; bus < 8; bus++) {
+ for (device = 0; device < 32; device++) {
+ uint32 maxFunction = 1;
+ Bool bridge = FALSE;
+
+ data = PCICfgRW(MKPCI(bus, device, 0), 0, 0, PCI_READ);
+
+ if ((data & 0xffff) == 0xffff) {
+ continue;
+ }
+
+ /* Check for multifunction */
+ data = PCICfgRW(MKPCI(bus, device, 0), 0x0c, 0, PCI_READ);
+
+ if (((data >> 16) & 0xff) & 0x80) {
+ maxFunction = 8;
+ }
+
+ if (((data >> 16) & 0x7f) == 1) {
+ bridge = TRUE;
+ }
+
+
+ for (fcn = 0; fcn < maxFunction; fcn++) {
+ struct PCIDev *new;
+ uint32 k, reg, bdf = MKPCI(bus, device, fcn);
+
+ data = PCICfgRW(bdf, 0, 0, PCI_READ);
+
+ if ((data & 0xffff) == 0xffff) {
+ continue;
+ }
+
+ pciAddress = bdf;
+ pciData = data;
+ asm(".global HavePCI\nHavePCI:\n");
+
+ new = alloc(sizeof(struct PCIDev));
+
+ if (pciRoot == NULL) {
+ pciRoot = new;
+ } else {
+ last->next = new;
+ }
+ last = new;
+
+ new->next = NULL;
+ new->bdf = bdf;
+ new->vendor = data & 0xffff;
+ new->device = data >> 16;
+
+ data = PCICfgRW(bdf, 0x04, 0, PCI_READ);
+ new->command = data & 0xffff;
+ new->status = data >> 16;
+
+ data = PCICfgRW(bdf, 0x08, 0, PCI_READ);
+ new->revision = data & 0xff;
+ new->baseClass = (data >> 24) & 0xff;
+ new->subClass = (data >> 16) & 0xff;
+ new->regInterface = (data >> 8) & 0xff;
+
+ data = PCICfgRW(bdf, 0x0c, 0, PCI_READ);
+ new->cacheLine = data & 0xff;
+ new->latTimer = (data >> 8) & 0xff;
+ new->headerType = (data >> 16) & 0xff;
+ new->bist = (data >> 24) & 0xff;
+
+ data = PCICfgRW(bdf, 0x2c, 0, PCI_READ);
+ new->subsystemVendor = data & 0xffff;
+ new->subsystemDevice = data >> 16;
+
+ data = PCICfgRW(bdf, 0x3c, 0, PCI_READ);
+ new->irqPin = data & 0xff;
+ new->irqLine = (data >> 8) & 0xff;
+
+ TEST_VPROBE(new->irqPin, new->irqLine);
+
+ new->ROMbase = PCICfgRW(bdf, 0x30, 0, PCI_READ);
+
+ if (HasBAR(new->baseClass)) {
+ for (k = 0, reg = 0x10; reg <= 0x24; k++, reg += 4) {
+ new->BAR[k] = PCICfgRW(bdf, reg, 0, PCI_READ);
+ new->size[k] = (new->BAR[k] == 0) ? 0 : GetBARSize(bdf, reg);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/* void */
+/* EnumeratePCIBridges(void) */
+/* { */
+
+/* } */
+
+
+/*
+ * PCI IRQ Routing Table Specification can be found at
+ * http://www.microsoft.com/whdc/archive/pciirq.mspx
+ *
+ * The PIR is probably outdated and the ACPI table should probably be
+ * used instead.
+ *
+ */
+
+
+#define PIRBASE 0x0f0000
+#define PIRLIMIT 0x100000
+/* "$PIR" */
+#define PIR 0x52495024
+
+struct PciIrqRoutingSlot {
+ uint8 bus; /* PCI bus number */
+ uint8 device; /* PCI device number (upper 5 bits) */
+ uint8 intALink; /* Link value for INTA# */
+ uint16 intABits; /* IRQ bitmap for INTA# */
+ uint8 intBLink; /* Link value for INTB# */
+ uint16 intBBits; /* IRQ bitmap for INTB# */
+ uint8 intCLink; /* Link value for INTC# */
+ uint16 intCBits; /* IRQ bitmap for INTC# */
+ uint8 intDLink; /* Link value for INTD# */
+ uint16 intDBits; /* IRQ bitmap for INTD# */
+ uint8 slot; /* slot number */
+ uint8 reserved;
+} __attribute__((packed));
+
+struct PciIrqRouting {
+ uint32 sig; /* signature */
+ uint16 version; /* version (1.0) */
+ uint16 size; /* table size */
+ uint8 bus; /* PCI interrupt router's bus */
+ uint8 devFunc; /* PCI interrupt router's device and function (5/3) */
+ uint16 xirq; /* PCI exclusive IRQs (PCI only IRQ bitmap) */
+ uint32 compat; /* Compatible PCI interrupt router (vendor/device ID)*/
+ uint32 miniport; /* Data passed to IRQ miniport's Initialize() function */
+ uint8 reserved[11];
+ uint8 checksum; /* sum(table) % 256 == 0 (including this checksum) */
+ struct PciIrqRoutingSlot entries[0];
+} __attribute__((packed));
+
+
+struct PciIrqRouting *routingTable; // vprobes
+
+void
+RouteIRQs(void)
+{
+ struct PciIrqRouting *table;
+ VA m;
+
+ /*
+ * Search for the IRQ routing table (the region is already identity mapped).
+ */
+ for (m = PIRBASE; m < PIRLIMIT; m += 16) {
+ if (*(uint32 *)m == PIR) {
+ table = (struct PciIrqRouting *)m;
+ break;
+ }
+ }
+
+ if (m >= PIRLIMIT) {
+ return;
+ }
+
+ routingTable = table;
+ //asm(".global RouteIRQ\nRouteIRQ:\n");
+}
+
+
+void
+PCIMMap(void)
+{
+
+}
+
+
+void
+MapPCI(void)
+{
+ pciRoot = NULL;
+
+ EnumeratePCI();
+/* EnumeratePCIBridges(); */
+ RouteIRQs();
+
+ /* Map memory used by PCI devices (have to remap the framebuffer). */
+ PCIMMap();
+}
diff --git a/Marmot/task.c b/Marmot/task.c
new file mode 100644
index 0000000..4a80670
--- /dev/null
+++ b/Marmot/task.c
@@ -0,0 +1,179 @@
+/*
+ * task.c --
+ *
+ * Basic task handling.
+ */
+
+
+#include <marmot.h>
+
+typedef enum {
+ SCHED_PRIORITY_IRQ,
+ SCHED_PRIORITY_INTERRUPT,
+ SCHED_PRIORITY0,
+ SCHED_PRIORITY1,
+ SCHED_PRIORITY2,
+ SCHED_PRIORITY3,
+ SCHED_PRIORITY4,
+ SCHED_PRIORITY5,
+ SCHED_PRIORITY6,
+ SCHED_PRIORITY7
+} SchedPriority;
+
+
+typedef struct {
+ UReg rax;
+ UReg rbx;
+ UReg rcx;
+ UReg rdx;
+ UReg rdi;
+ UReg rsi;
+ UReg rbp;
+ UReg rsp;
+ UReg r8;
+ UReg r9;
+ UReg r10;
+ UReg r11;
+ UReg r12;
+ UReg r13;
+ UReg r14;
+ UReg r15;
+} Registers;
+
+
+struct task {
+ uint64 id;
+ Registers regs;
+ UReg cr3;
+};
+
+
+void
+SaveTask(void)
+{
+
+}
+
+void
+SwitchToTaskStack(void)
+{
+
+}
+
+void
+SwitchToTask(void)
+{
+
+}
+
+
+typedef struct _DFCArgs {
+ uint64 a1;
+ uint64 a2;
+ uint64 a3;
+ uint64 a4;
+} *DFCArgs;
+
+typedef void (*DFCFcn)(DFCArgs);
+
+typedef struct _DFC {
+ struct _DFC *next;
+ DFCFcn fcn;
+ DFCArgs args;
+} DFC;
+
+DFC *dfcHead;
+
+
+void
+RunDFC(DFCFcn fcn, DFCArgs args)
+{
+
+}
+
+
+/*
+ * This is only called from the timer interrupt. As it doesn't
+ * return, it's necessary to unmask the timer IRQ prior to switching
+ * to the new task.
+ */
+
+void
+TaskSchedule(uint64 timerIrq)
+{
+ DFC *dfc;
+
+ SaveTask();
+ SwitchToTaskStack();
+
+ /*
+ * Run all DFCs now.
+ */
+
+ sti(); // timer irq is still masked
+
+ for (dfc = dfcHead; dfc != NULL; dfc = dfcHead) {
+ dfcHead = dfc->next;
+
+ RunDFC(dfc->fcn, dfc->args);
+ free(dfc->args);
+ free(dfc);
+ }
+
+ /*
+ * Run regular tasks now.
+ */
+
+ // XXX
+
+
+ UnmaskPIC(timerIrq - IRQBASE);
+ SwitchToTask(); // executes an iretq
+}
+
+
+typedef void (*Task)(void);
+
+void
+TaskStart(Task t)
+{
+ /*
+ * Allocate new stack.
+ */
+
+}
+
+
+void
+TaskInit(void)
+{
+ dfcHead = NULL;
+
+ /*
+ * Create task stack
+ * Create runqueues
+ * Hook TaskSchedule into the timer interrupt.
+ */
+}
+
+
+
+
+/*
+ * Defer --
+ *
+ * Create a deferred function call. This DFC is placed on the
+ * runqueue of the specified priority and, once scheduled, is
+ * passed the appropriate args.
+ *
+ * DFCs run synchronously on the stack of the scheduler which
+ * makes them especially convenient for IRQ/fault handling.
+ *
+ * The DFCArgs that is passed
+ */
+
+void
+Defer(SchedPriority p, DFCFcn dfc, DFCArgs *args)
+{
+
+}
diff --git a/Marmot/types.h b/Marmot/types.h
new file mode 100644
index 0000000..921a684
--- /dev/null
+++ b/Marmot/types.h
@@ -0,0 +1,44 @@
+/*
+ * types.h --
+ *
+ * Basic marmot types.
+ *
+ */
+
+#ifndef _TYPES_H
+#define _TYPES_H
+
+
+
+#ifndef ASM
+
+typedef long long int int64;
+typedef unsigned long long int uint64;
+typedef int int32;
+typedef unsigned int uint32;
+typedef short int int16;
+typedef unsigned short int uint16;
+typedef signed char int8;
+typedef unsigned char uint8;
+
+typedef uint64 PA;
+typedef uint64 VA;
+typedef uint64 UReg;
+typedef uint8 Bool;
+typedef uint64 size_t;
+
+#define TRUE ((Bool)1)
+#define FALSE ((Bool)0)
+
+
+typedef uint32 Color;
+typedef uint64 Length;
+
+typedef struct {
+ uint64 x;
+ uint64 y;
+} __attribute__((packed)) Point;
+
+#endif
+
+#endif
diff --git a/Marmot/util.S b/Marmot/util.S
new file mode 100644
index 0000000..c4c5905
--- /dev/null
+++ b/Marmot/util.S
@@ -0,0 +1,122 @@
+ /*
+ * util.S --
+ *
+ * Various generic utility functions.
+ */
+
+
+ .code64
+ .section .text
+
+ /*
+ * bzero --
+ * bfill --
+ *
+ * void bzero(void *s, uint64 n);
+ * void bfill(void *s, uint64 n, uint8 val);
+ *
+ * Set the first n bytes of s to 0 or to val.
+ */
+
+ .global bzero
+bzero: pushq %rbp
+ movq %rsp, %rbp
+
+ xorq %rdx, %rdx
+ jmp 1f
+
+
+ .global bfill
+bfill: pushq %rbp
+ movq %rsp, %rbp
+
+ /* copy %dl to each byte of %rdx */
+ movzbq %dl, %rdx
+ movq %rdx, %rax
+ clc
+ shll $8, %edx
+ orl %eax, %edx
+ /* 2 bytes done */
+ movl %edx, %eax
+ shll $16, %edx
+ orl %eax, %edx
+ /* 4 bytes done */
+ movq %rdx, %rax
+ shlq $32, %rdx
+ orq %rax, %rdx
+ /* all 8 done */
+
+ /* set bytes while adjusting s up to 8 byte boundary */
+1: testl $7, %esi
+ jz 1f
+
+ movb %dl, (%rdi)
+ decq %rsi
+ incq %rdi
+ jmp 1b
+
+1: /* zero bytes 8 at a time */
+
+ testq $-8, %rsi
+ jz 1f
+
+ movq %rdx, (%rdi)
+ subq $8, %rsi
+ addq $8, %rdi
+ jmp 1b
+
+1: /* zero out the remainder */
+ testl $7, %esi
+ jz 1f
+
+ movb %dl, (%rdi)
+ decq %rsi
+ incq %rdi
+ jmp 1b
+
+1: leave
+ ret
+
+
+ /*
+ * bcopy --
+ *
+ * void bcopy(void *s, void *d, uint64 n);
+ *
+ * Copy n bytes from s to d.
+ */
+
+ .global bcopy
+bcopy: pushq %rbp
+ movq %rsp, %rbp
+
+ cld
+ xchgq %rdi, %rsi
+ movq %rdx, %rcx
+ rep movsb
+
+ leave
+ ret
+
+
+ /*
+ * strlen --
+ *
+ * Return length of a string.
+ *
+ * uint64 strlen(char *s);
+ */
+ .global strlen
+strlen: pushq %rbp
+ movq %rsp, %rbp
+
+ pushq %rdi
+ xorl %eax, %eax
+ cld
+ repne scasb
+ popq %rax
+ subq %rax, %rdi # d - d - s
+ movq %rdi, %rax
+
+ leave
+ ret
diff --git a/Marmot/vesa.S b/Marmot/vesa.S
new file mode 100644
index 0000000..c6b652f
--- /dev/null
+++ b/Marmot/vesa.S
@@ -0,0 +1,420 @@
+ /*
+ * vesa.S --
+ *
+ * Interface to VESA.
+ */
+
+#define VESA_MAGIC 0x41534556
+#define MAX_MODES 256
+#define MODE_1280_1024_32 0x0144
+#define MODE_1280_1024_24 0x011b
+#define MODE_1024_768_32 0x0141
+#define MODE_1024_768_24 0x0118
+#define MODE_800_600_32 0x0140
+#define MODE_800_600_24 0x0114
+
+
+ .section .text, "xa"
+
+ .code16
+
+ .global GetVESAInfo
+GetVESAInfo:
+ xorw %ax, %ax
+ movw %ax, %es
+ movw $0x4f00, %ax
+ movw $VbeInfoBlock, %di
+
+ int $0x10
+
+ cmpw $0x004f, %ax
+ jne BadVESA
+ cmpl $VESA_MAGIC, VbeInfoBlock
+ je 1f
+
+ movw $noVBEMsg, %si
+ jmp BadVESA
+
+ /* Search mode list for preferred modes */
+1: movw bootPreferredVideoMode, %bx
+ movw %bx, VideoModeList
+
+ xorl %esi, %esi
+ movw %si, %es
+ movw VideoModePtr, %si
+ movw (VideoModePtr + 2), %ax
+ movw %ax, %ds
+
+ .global ModeLoop
+ModeLoop:
+ movl %ds:(%esi,%ecx,2), %ebx
+ cmpw $0xffff, %bx
+ je 1f
+ call CheckMode
+ incw %cx
+ jmp ModeLoop
+
+
+ /* restore ds */
+1: xorw %ax, %ax
+ movw %ax, %ds
+
+
+ /* Find the first present entry in preferred mode list */
+
+ movw $((VideoModeListEnd - VideoModeList) >> 1), %cx
+ movw $VideoModeList, %si
+ xorw %bx, %bx
+
+1: testw $0x8000, (%si)
+ jz 2f
+
+ movw (%si), %bx
+ andw $0x7fff, %bx
+ jmp 1f
+
+2: addw $2, %si
+ loop 1b
+
+ testw %bx, %bx
+ jnz 1f
+
+ movw $noPreferredModeMsg, %si
+ jmp BadVESA
+
+
+1: /* save current mode */
+ pushw %bx
+ movw $0x4f03, %ax
+ int $0x10
+ movw %bx, VESASavedMode
+
+ /* get preferred mode info */
+ movw $0x4f01, %ax
+ popw %cx
+ orw $0x4000, %cx /* linear/flat frame buffer */
+ pushw %cx
+ movw $VESAModeInfo, %di
+ int $0x10
+ cmpw $0x004f, %ax
+ je 1f
+
+ popw %bx
+ movw $noModeInfoMsg, %si
+ jmp BadVESA
+
+ /* set preferred mode */
+1: movw $0x4f02, %ax
+ popw %bx
+ .global vesa
+vesa:
+# orw $0x4000, %bx /* linear/flat frame buffer */
+ int $0x10
+ cmpb 1, %ah
+ jne 1f
+
+ movw $badModeMsg, %si
+ jmp BadVESA
+
+1: /* Get EDID info (XXX: move up) */
+ call GetEDID
+
+
+ clc
+ ret
+
+BadVESAModeSwitch:
+ pushw %si
+ movw $0x4f02, %ax
+ movw VESASavedMode, %bx
+ int $0x10
+ popw %si
+BadVESA:
+ stc
+ ret
+
+
+ /*
+ * CheckMode --
+ *
+ * Iterate through VideoModeList, checking for a match with
+ * %bx. If one is found, set the high bit of the matching
+ * entry.
+ * can't use %ds, can only clobber %ax
+ */
+
+CheckMode:
+ testw %bx, %bx
+ jnz 1f
+ ret
+
+1: pushw %cx
+ pushw %dx
+ pushw %di
+
+ movw $((VideoModeListEnd - VideoModeList) >> 1), %cx
+ movw $VideoModeList, %di
+
+1: movw %es:(%di), %dx
+ cmpw %bx, %dx
+ jne 2f
+
+ orw $0x8000, %dx
+ movw %dx, %es:(%di)
+
+2: addw $2, %di
+ loop 1b
+
+ popw %di
+ popw %dx
+ popw %cx
+ ret
+
+ /*
+ * GetEDID --
+ *
+ * Get EDID info for the attached monitor. This will then be
+ * used to choose the preferred VESA mode.
+ *
+ * Clobbers all registers (%ds and %es are both reset to 0).
+ *
+ */
+GetEDID:
+ /* Get capabilities */
+ xorw %di, %di
+ movw %di, %es
+ movw $0x4f15, %ax
+ xorw %bx, %bx
+ xorw %cx, %cx /* port 0 only */
+ int $0x10
+ cmpw $0x004f, %ax
+ je 1f
+
+ /* VMW VGA BIOS doesn't support EDID... */
+ movw $0, EDIDCapabilities
+ ret
+
+1: movw %bx, EDIDCapabilities
+
+ /* Get monitor properties */
+ movw $0x4f15, %ax
+ movw $1, %bx
+ xorw %cx, %cx
+ xorw %dx, %dx
+ movw $EDIDBlock, %di
+ int $0x10
+ cmpw $0x004f, %ax
+ je 1f
+ movw $0, EDIDCapabilities
+1: ret
+
+
+ .section .data
+
+ .align 4
+
+ .global VideoModeList
+VideoModeList:
+ /* high bit of each mode will be set if the mode is present */
+ .word 0 /* first entry is bootPreferredVideoMode */
+ .word MODE_1280_1024_32
+ .word MODE_1280_1024_24
+ .word MODE_1024_768_32
+ .word MODE_1024_768_24
+ .word MODE_800_600_32
+ .word MODE_800_600_24
+VideoModeListEnd:
+
+ .align 1
+noVBEMsg:
+ .asciz "VBE BIOS doesn't seem to be present!"
+noPreferredModeMsg:
+ .asciz "Preferred video mode(s) not supported!"
+noModeInfoMsg:
+ .asciz "Unable to get preferred video mode info!"
+badModeMsg:
+ .asciz "Unable to set preferred video mode!"
+
+
+ .section .bss
+
+ /* VBE info block */
+ .global VbeInfoBlock
+VbeInfoBlock:
+ .global VbeSignature
+VbeSignature:
+ .long 0
+ .global VbeVersion
+VbeVersion:
+ .word 0
+ .global OemStringPtr
+OemStringPtr:
+ .long 0
+ .global Capabilities
+Capabilities:
+ .long 0
+ .global VideoModePtr
+VideoModePtr:
+ .long 0
+ .global TotalMemory
+TotalMemory:
+ .word 0
+ .global OemSoftwareRev
+OemSoftwareRev:
+ .word 0
+ .global OemVendorNamePtr
+OemVendorNamePtr:
+ .long 0
+ .global OemProductNamePtr
+OemProductNamePtr:
+ .long 0
+ .global OemProductRevPtr
+OemProductRevPtr:
+ .long 0
+ .fill 222, 1, 0
+OemData:
+ .fill 256, 1, 0
+
+ .align 4
+
+ .global VESASavedMode
+VESASavedMode:
+ .word 0
+
+
+ /*
+ * VESAModeInfo --
+ *
+ * Block of info returned by function 1. This structure is
+ * filled in with the info for the preferred mode in use.
+ *
+ */
+ .global VESAModeInfo
+VESAModeInfo:
+ /* common to all VBE revisions */
+ModeAttributes:
+ .word 0 # 00bb (1011 1011)
+WinAAttributes:
+ .byte 0 # 07
+WinBAttributes:
+ .byte 0 # 00
+WinGranularity:
+ .word 0 # 0040
+WinSize:
+ .word 0 # 0040
+WinASegment:
+ .word 0 # a000
+WinBSegment:
+ .word 0 # 0000
+WinFuncPtr:
+ .long 0 # c000:7121
+BytesPerScanLine: # off16
+ .word 0 # 0500
+
+ /* VBE 1.2+ */
+ .global xResolution
+xResolution:
+ .word 0 # 0140 (320)
+ .global yResolution
+yResolution:
+ .word 0 # 0190 (400)
+XCharSize:
+ .byte 0 # 10
+YCharSize:
+ .byte 0 # 08
+NumberOfPlanes:
+ .byte 0 # 01
+ .global bitsPerPixel
+bitsPerPixel:
+ .byte 0 # 20
+NumberOfBanks:
+ .byte 0 # 01
+MemoryModel:
+ .byte 0 # 06
+BankSize:
+ .byte 0 # 00
+NumberOfImagePages:
+ .byte 0 # 00
+Reserved1:
+ .byte 0 # 01
+
+ /* direct/6 and YUV/7 */
+ .global redMaskSize
+redMaskSize:
+ .byte 0 # 08
+ .global redFieldPosition
+redFieldPosition: #
+ .byte 0 # 10
+ .global greenMaskSize
+greenMaskSize:
+ .byte 0 # 08
+ .global greenFieldPosition
+greenFieldPosition:
+ .byte 0 # 08
+ .global blueMaskSize
+blueMaskSize:
+ .byte 0 # 08
+ .global blueFieldPosition
+blueFieldPosition:
+ .byte 0 # 00
+ .global rsvdMaskSize
+rsvdMaskSize:
+ .byte 0 # 08
+ .global rsvdFieldPosition
+rsvdFieldPosition:
+ .byte 0 # 18
+DirectColorModeInfo:
+ .byte 0 # 00
+
+ /* VBE 2.0+ */
+ .global physBasePtr
+physBasePtr:
+ .long 0 # d0000000
+Reserved2:
+ .long 0
+Reserved3:
+ .word 0
+
+ /* VBE 3.0+ */
+LinBytesPerScanLine:
+ .word 0
+BnkNumberOfImagePages:
+ .byte 0
+LinNumberOfImagePages:
+ .byte 0
+LinRedMaskSize:
+ .byte 0
+LinRedFieldPosition:
+ .byte 0
+LinGreenMaskSize:
+ .byte 0
+LinGreenFieldPosition:
+ .byte 0
+LinBlueMaskSize:
+ .byte 0
+LinBlueFieldPosition:
+ .byte 0
+LinRsvdMaskSize:
+ .byte 0
+LinRsvdFieldPosition:
+ .byte 0
+MaxPixelClock:
+ .long 0
+Reserved4:
+ .fill 189, 1, 0
+VESAModeInfoEnd:
+
+
+ /*
+ * EDID info --
+ *
+ */
+
+ .align 4
+ .global EDIDCapabilities
+EDIDCapabilities:
+ .word 0
+
+ .global EDIDBlock
+EDIDBlock:
+ .fill 256, 1, 0
diff --git a/Marmot/video.c b/Marmot/video.c
new file mode 100644
index 0000000..6e24f7b
--- /dev/null
+++ b/Marmot/video.c
@@ -0,0 +1,562 @@
+/*
+ * video.c --
+ *
+ * Video interface.
+ */
+
+#include <marmot.h>
+
+
+struct FontTable {
+ /* glyph is the 32 bit address of the glyph */
+ uint32 glyph;
+ /* width and height of the glyph in pixels */
+ uint16 w;
+ uint16 h;
+} __attribute__((packed));
+
+extern struct FontTable fontTable[];
+
+extern uint8 *frameBuffer;
+extern uint64 frameBufferSize;
+
+extern uint32 physBasePtr;
+extern uint8 bitsPerPixel;
+extern uint16 xResolution;
+extern uint16 yResolution;
+extern uint8 redMaskSize;
+extern uint8 redFieldPosition;
+extern uint8 greenMaskSize;
+extern uint8 greenFieldPosition;
+extern uint8 blueMaskSize;
+extern uint8 blueFieldPosition;
+extern uint8 rsvdMaskSize;
+extern uint8 rsvdFieldPosition;
+
+static uint64 rMask;
+static uint64 gMask;
+static uint64 bMask;
+static uint64 aMask;
+
+
+/*
+ * SetPixel --
+ *
+ * Set the pixel at x,y to the specified ARGB color.
+ */
+
+void
+SetPixel(Color color, Point p)
+{
+ uint32 pixelValue = 0;
+ int bytesPerPixel = 1;
+ uint8 *pixel;
+
+
+ /* Convert color into local colorspace. */
+
+ switch (bitsPerPixel) {
+ case 32:
+ case 24:
+ bytesPerPixel = 4;
+ pixelValue = (uint32)color;
+ break;
+ case 16:
+ case 15:
+ /* 5:6:5 */
+ /* 1:5:5:5 */
+ pixelValue = (uint32)(((color >> redFieldPosition) & rMask) |
+ ((color >> greenFieldPosition) & gMask) |
+ ((color >> blueFieldPosition) & bMask) |
+ ((color >> rsvdFieldPosition) & aMask));
+ bytesPerPixel = 2;
+ break;
+ case 8:
+ case 4:
+ UNIMPLEMENTED("8 or 4 bits per pixel");
+ pixelValue = 0x80;
+ bytesPerPixel = 1;
+ }
+
+ /* Find pixel address */
+ pixel = frameBuffer + bytesPerPixel * (p.x + p.y * xResolution);
+
+ switch (bytesPerPixel) {
+ case 4:
+ *((uint32 *)pixel) = pixelValue;
+ break;
+ case 2:
+ *((uint16 *)pixel) = (uint16)pixelValue;
+ break;
+ case 1:
+ *((uint8 *)pixel) = (uint8)pixelValue;
+ break;
+ }
+}
+
+
+Color
+GetPixel(Point p)
+{
+ Color c = COLOR_BLACK;
+ uint16 pix16;
+ uint8 *pixel;
+
+ switch (bitsPerPixel) {
+ case 32:
+ case 24:
+ pixel = frameBuffer + 4 * (p.x + p.y * xResolution);
+ c = *((uint32 *)pixel);
+ break;
+ case 16:
+ case 15:
+ pixel = frameBuffer + 2 * (p.x + p.y * xResolution);
+ pix16 = *((uint16 *)pixel);
+ c = (((pix16 & rMask) << redFieldPosition) |
+ ((pix16 & gMask) << greenFieldPosition) |
+ ((pix16 & bMask) << blueFieldPosition) |
+ ((pix16 & aMask) << rsvdFieldPosition));
+ break;
+ case 8:
+ case 4:
+ UNIMPLEMENTED("8 or 4 bits per pixel");
+ break;
+ }
+
+ return c;
+}
+
+
+/*
+ * ColorRectangle --
+ *
+ * Set a rectangular area to be the specified color.
+ */
+
+void
+ColorRectangle(Color color, Point c0, Point c1)
+{
+ uint64 xLow, xHigh, yLow, yHigh, x, y;
+
+ if (c0.x == c1.x || c0.y == c1.y) {
+ return;
+ }
+
+ if (c0.x < c1.x) {
+ xLow = c0.x;
+ xHigh = c1.x;
+ } else {
+ xLow = c1.x;
+ xHigh = c0.x;
+ }
+ if (c0.y < c1.y) {
+ yLow = c0.y;
+ yHigh = c1.y;
+ } else {
+ yLow = c1.y;
+ yHigh = c0.y;
+ }
+
+ for (x = xLow; x <= xHigh; x++) {
+ for (y = yLow; y <= yHigh; y++) {
+ Point p;
+
+ p.x = x;
+ p.y = y;
+
+ SetPixel(color, p);
+ }
+ }
+}
+
+void
+ColorCircle(Color color, Point c, Length r)
+{
+ uint64 xl, xr, yt, yb;
+ Point p;
+
+ if (r == 0) {
+ return;
+ }
+
+ /* correct borders */
+ if (r > c.x) {
+ xl = r - c.x;
+ } else {
+ xl = 0;
+ }
+ if (c.x + r > xResolution - 1) {
+ xr = xResolution - 1;
+ } else {
+ xr = c.x + r;
+ }
+ if (r > c.y) {
+ yt = r - c.y;
+ } else {
+ yt = 0;
+ }
+ if (c.y + r > yResolution - 1) {
+ yb = yResolution - 1;
+ } else {
+ yb = c.y + r;
+ }
+
+ for (p.x = xl; p.x <=xr; p.x++) {
+ for (p.y = yt; p.y <= yb; p.y++) {
+ uint64 xx, yy;
+
+ /* limit x and y to quadrant 4 */
+ if (p.x < c.x) {
+ xx = c.x - p.x;
+ } else {
+ xx = p.x - c.x;
+ }
+ if (p.y < c.y) {
+ yy = c.y - p.y;
+ } else {
+ yy = p.y - c.y;
+ }
+
+ if (xx * xx + yy * yy < r * r) {
+ SetPixel(color, p);
+ }
+ }
+ }
+}
+
+
+/*
+ * SetBootBackground --
+ *
+ * Set the screen background to the default boot color.
+ */
+
+void
+SetBootBackground(void)
+{
+ Point p;
+
+ for (p.x = 0; p.x < xResolution; p.x++) {
+ for (p.y = 0; p.y < yResolution; p.y++) {
+ SetPixel(BOOT_BACKGROUND_COLOR, p);
+ }
+ }
+}
+
+
+/*
+ * VideoInit --
+ *
+ * Calculate frame buffer size and map it into the virtual
+ * address space.
+ */
+
+void
+VideoInit(void)
+{
+ uint64 bytesPerPixel = 0;
+
+ /*
+ * Identity map the frame buffer.
+ */
+
+ frameBuffer = (uint8 *)(VA)physBasePtr;
+
+ switch (bitsPerPixel) {
+ case 32:
+ case 24:
+ bytesPerPixel = 4;
+ break;
+ case 16:
+ case 15:
+ bytesPerPixel = 2;
+ break;
+ default:
+ bytesPerPixel = 1;
+ }
+
+ frameBufferSize = xResolution * yResolution * bytesPerPixel;
+
+ MapIORegion((PA)frameBuffer,
+ (PA)(frameBuffer + frameBufferSize),
+ "frameBuffer");
+
+
+ /*
+ * Init pixel masks.
+ */
+
+ rMask = ((1ULL << redMaskSize) - 1) << redFieldPosition;
+ gMask = ((1ULL << greenMaskSize) - 1) << greenFieldPosition;
+ bMask = ((1ULL << blueMaskSize) - 1) << blueFieldPosition;
+ aMask = (rsvdMaskSize ? (1ULL << rsvdMaskSize) - 1 : 0) << rsvdFieldPosition;
+
+
+ /*
+ * Set a pleasing background color.
+ */
+
+ SetBootBackground();
+}
+
+
+#define PIXEL_VALUE(glyph,p) ((((glyph)[(p) >> 3]) & \
+ (1 << (7 - ((p) % 8)) )) >> \
+ (7 - ((p) % 8)))
+
+/*
+ * PrintMessage --
+ *
+ * Display msg at pixel coordinates x,y.
+ */
+
+void
+PrintMessage(Color color, Point where, char *msg)
+{
+ int c;
+ uint64 xOff = 0; /* offset from start of message */
+
+ for (c = 0; msg[c]; c++) {
+ uint8 *glyph;
+ uint64 xp, yp;
+ int p, ch;
+
+ ch = msg[c];
+
+ glyph = (uint8 *)((VA)fontTable[ch].glyph);
+ xp = yp = 0;
+
+ /* loop over pixels */
+ for (p = 0; p < fontTable[ch].w * fontTable[ch].h; p++) {
+
+ if (PIXEL_VALUE(glyph, p) == 1) {
+ Point p;
+
+ p.x = where.x + xOff + xp;
+ p.y = where.y + yp;
+
+ SetPixel(color, p);
+ }
+
+ xp++;
+ if ((xp % fontTable[ch].w) == 0) {
+ xp = 0;
+ yp++;
+ }
+ }
+
+ xOff += fontTable[ch].w;
+ }
+}
+
+/*
+ * Cursor handling.
+ *
+ * Register a callback with irq12 (will be a deferred function call).
+ * When the cursor moves, the old cursor spot is replaced with its
+ * saved spot, then the new cursor spot is saved and the cursor is
+ * drawn.
+ *
+ */
+
+#include "cursor.xbm"
+
+static Color savedCursor[cursor_width][cursor_height];
+static struct {
+ int32 x;
+ int32 y;
+ int32 z;
+ unsigned int button1:1;
+ unsigned int button2:1;
+ unsigned int button3:1;
+ unsigned int button4:1;
+ unsigned int button5:1;
+} cursorInfo;
+
+
+static CbID cursorCbId;
+
+void
+RestoreCursorArea(void)
+{
+ int32 x, y, sx, sy;
+ Point p;
+
+ for (x = 0; x < cursor_width; x++) {
+ for (y = 0; y < cursor_height; y++) {
+ sx = cursorInfo.x - cursor_x_hot + x;
+ sy = cursorInfo.y - cursor_y_hot + y;
+
+ if (sx < 0 || sy < 0 || sx > xResolution || sy > yResolution) {
+ continue;
+ }
+
+ p.x = sx;
+ p.y = sy;
+ SetPixel(savedCursor[x][y], p);
+ }
+ }
+}
+
+
+void
+SaveCursorArea(void)
+{
+ int32 x, y, sx, sy;
+ Point p;
+
+ for (x = 0; x < cursor_width; x++) {
+ for (y = 0; y < cursor_height; y++) {
+ sx = cursorInfo.x - cursor_x_hot + x;
+ sy = cursorInfo.y - cursor_y_hot + y;
+
+ if (sx < 0 || sy < 0 || sx > xResolution || sy > yResolution) {
+ continue;
+ }
+
+ p.x = sx;
+ p.y = sy;
+ savedCursor[x][y] = GetPixel(p);
+ }
+ }
+}
+
+
+/* assume 16x16 */
+#define CURSOR_ISSET(x,y) ((cursor_bits[(x)] >> y) & 1)
+
+void
+DisplayCursor(void)
+{
+ int32 x, y, sx, sy;
+ Point p;
+
+ for (x = 0; x < cursor_width; x++) {
+ for (y = 0; y < cursor_height; y++) {
+ sx = cursorInfo.x - cursor_x_hot + x;
+ sy = cursorInfo.y - cursor_y_hot + y;
+
+ if (sx < 0 || sy < 0 || sx > xResolution || sy > yResolution) {
+ continue;
+ }
+
+ p.x = sx;
+ p.y = sy;
+
+ if (!CURSOR_ISSET(x,y)) {
+ continue;
+ }
+
+ SetPixel(COLOR_BLACK, p);
+ }
+ }
+}
+
+
+void
+DoButtons(int b1, int b2, int b3)
+{
+ Point p;
+ Length r;
+
+ p.x = 520;
+ p.y = 25;
+ r = 20;
+
+ if (b1) {
+ ColorCircle(COLOR_BLUE, p, r);
+ } else {
+ ColorCircle(COLOR_PLEASING_GREEN, p, r);
+ }
+ p.x += 40;
+ if (b2) {
+ ColorCircle(COLOR_ROBINs_PURPLE, p, r);
+ } else {
+ ColorCircle(COLOR_PLEASING_GREEN, p, r);
+ }
+ p.x += 40;
+ if (b3) {
+ ColorCircle(COLOR_RED, p, r);
+ } else {
+ ColorCircle(COLOR_PLEASING_GREEN, p, r);
+ }
+}
+
+
+void
+DoCursor(uint8 *packet, uint64 N)
+{
+ int32 xd = 0, yd = 0;
+
+ RestoreCursorArea();
+
+ /* update coordinates */
+ /*
+ * N == 3
+ *
+ * Byte 1: Yof Xof Ys Xs 1 b1 b2 b0
+ * Byte 2: Xmove
+ * Byte 3: Ymove
+ *
+ * N == 4
+ *
+ * Byte 1: Yof Xof Ys Xs 1 b1 b2 b0
+ * Byte 2: Xmove
+ * Byte 3: Ymove
+ * Byte 4: Zmove
+ */
+
+ xd |= packet[1];
+ if (packet[0] & 0x10) {
+ xd |= 0xffffff00;
+ }
+ yd |= packet[2];
+ if (packet[0] & 0x20) {
+ yd |= 0xffffff00;
+ }
+
+ /* XXX do Z */
+
+ cursorInfo.x += xd;
+ cursorInfo.y -= yd;
+
+ if (cursorInfo.x < 0) {
+ cursorInfo.x = 0;
+ } else if (cursorInfo.x > xResolution) {
+ cursorInfo.x = xResolution;
+ }
+ if (cursorInfo.y < 0) {
+ cursorInfo.y = 0;
+ } else if (cursorInfo.y > yResolution) {
+ cursorInfo.y = yResolution;
+ }
+
+ cursorInfo.button1 = packet[0] & 1;
+ cursorInfo.button2 = (packet[0] >> 2) & 1;
+ cursorInfo.button3 = (packet[0] >> 1) & 1;
+
+ /* draw some small circles */
+ DoButtons(cursorInfo.button1, cursorInfo.button2, cursorInfo.button3);
+
+ SaveCursorArea();
+ DisplayCursor();
+}
+
+
+void
+CursorInit(void)
+{
+ cursorInfo.x = xResolution / 2;
+ cursorInfo.y = yResolution / 2;
+ cursorInfo.z = 0;
+ cursorInfo.button1 = 0;
+ cursorInfo.button2 = 0;
+ cursorInfo.button3 = 0;
+ cursorInfo.button4 = 0;
+ cursorInfo.button5 = 0;
+
+ SaveCursorArea();
+ DisplayCursor();
+
+ cursorCbId = InstallMouseCB(DoCursor);
+}
diff --git a/Marmot/window.c b/Marmot/window.c
new file mode 100644
index 0000000..e123cb8
--- /dev/null
+++ b/Marmot/window.c
@@ -0,0 +1,37 @@
+/*
+ * window.c --
+ *
+ * Implementation of the windowing interface.
+ */
+
+
+typedef uint64 Window;
+
+typedef struct {
+ Color bg;
+ Color fg;
+ uint64 width;
+ uint64 height;
+ uint8 *fb;
+ uint64 fbWidth;
+ uint64 fbHeight;
+ char *title;
+ unsigned int hasFocus:1;
+ unsigned int drawBorder:1;
+} WParam;
+
+
+
+
+Window
+Window_Create(WParam *wp)
+{
+ if (wp->bg == COLOR_DEFAULT) {
+ wp->bg = COLOR_WINDOW_BACKGROUND;
+ }
+ if (wp->fg == COLOR_DEFAULT) {
+ wp->fg = COLOR_BLACK;
+ }
+
+}
+
diff --git a/README b/README
index 8828db9..b160dba 100644
--- a/README
+++ b/README
@@ -85,6 +85,10 @@ your tracks on Google Earth (that's what I wrote it for).
Very basic GeoTIFF viewer. Loads one file at a time, converts coordinates and such.
+## Marmot
+
+Experimental OS. Not complete, of course, but boots and runs just fine.
+
## matfun
Library for the HP48 (both S and G) that implements vectorized matrix