diff options
| author | Jon duSaint | 2022-05-03 16:36:47 -0700 |
|---|---|---|
| committer | Jon duSaint | 2022-05-03 16:36:47 -0700 |
| commit | 7c75c02f784be12343e2e4f82726f3a5f0ddb6a7 (patch) | |
| tree | ce0bea4ad2f88a77392efaf3d3c3b66a547f8459 | |
| parent | 88753ad637bec0c665a611be6e703a519b0660ad (diff) | |
Marmot: add old project
| -rw-r--r-- | Marmot/Makefile | 49 | ||||
| -rw-r--r-- | Marmot/alloc.c | 352 | ||||
| -rw-r--r-- | Marmot/apic.c | 53 | ||||
| -rw-r--r-- | Marmot/basic_font.hex | 256 | ||||
| -rw-r--r-- | Marmot/boot.S | 331 | ||||
| -rw-r--r-- | Marmot/cpu.c | 64 | ||||
| -rw-r--r-- | Marmot/cpu.h | 186 | ||||
| -rw-r--r-- | Marmot/cs.pl | 35 | ||||
| -rw-r--r-- | Marmot/cursor.xbm | 31 | ||||
| -rw-r--r-- | Marmot/device.c | 19 | ||||
| -rw-r--r-- | Marmot/dumpRegs.vp | 476 | ||||
| -rw-r--r-- | Marmot/font.S | 776 | ||||
| -rw-r--r-- | Marmot/forth.c | 23 | ||||
| -rw-r--r-- | Marmot/hexfont2data.pl | 87 | ||||
| -rw-r--r-- | Marmot/interrupts.S | 126 | ||||
| -rw-r--r-- | Marmot/irq.c | 711 | ||||
| -rw-r--r-- | Marmot/ld.conf | 26 | ||||
| -rw-r--r-- | Marmot/loader.S | 957 | ||||
| -rw-r--r-- | Marmot/marmot.bmp | bin | 0 -> 1920054 bytes | |||
| -rw-r--r-- | Marmot/marmot.h | 366 | ||||
| -rw-r--r-- | Marmot/marmot_os.xcf.bz2 | bin | 0 -> 904457 bytes | |||
| -rw-r--r-- | Marmot/mksym.pl | 30 | ||||
| -rw-r--r-- | Marmot/mm.c | 1064 | ||||
| -rw-r--r-- | Marmot/panic.c | 96 | ||||
| -rw-r--r-- | Marmot/pci.c | 343 | ||||
| -rw-r--r-- | Marmot/task.c | 179 | ||||
| -rw-r--r-- | Marmot/types.h | 44 | ||||
| -rw-r--r-- | Marmot/util.S | 122 | ||||
| -rw-r--r-- | Marmot/vesa.S | 420 | ||||
| -rw-r--r-- | Marmot/video.c | 562 | ||||
| -rw-r--r-- | Marmot/window.c | 37 | ||||
| -rw-r--r-- | README | 4 |
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 Binary files differnew file mode 100644 index 0000000..28b6636 --- /dev/null +++ b/Marmot/marmot.bmp 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 Binary files differnew file mode 100644 index 0000000..b629722 --- /dev/null +++ b/Marmot/marmot_os.xcf.bz2 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; + } + +} + @@ -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 |
