Merge "gitignore: Adding rule to ignore cscope files."
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8a4af05
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 9739379..b6c60f2 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -45,6 +45,7 @@
#include <baseband.h>
#include <target.h>
#include <mmc.h>
+#include <partition_parser.h>
#include <platform.h>
#include "recovery.h"
@@ -290,6 +291,7 @@
unsigned long long ptn = 0;
unsigned n = 0;
const char *cmdline;
+ int index = INVALID_PTN;
uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
@@ -298,14 +300,17 @@
goto unified_boot;
}
if (!boot_into_recovery) {
- ptn = mmc_ptn_offset((unsigned char *) "boot");
- if (ptn == 0) {
+ index = partition_get_index("boot");
+ ptn = partition_get_offset(index);
+ if(ptn == 0) {
dprintf(CRITICAL, "ERROR: No boot partition found\n");
return -1;
}
- } else {
- ptn = mmc_ptn_offset((unsigned char *) "recovery");
- if (ptn == 0) {
+ }
+ else {
+ index = partition_get_index("recovery");
+ ptn = partition_get_offset(index);
+ if(ptn == 0) {
dprintf(CRITICAL, "ERROR: No recovery partition found\n");
return -1;
}
@@ -529,14 +534,15 @@
{
unsigned long long ptn = 0;
unsigned int out[512] = {0};
+ int index = INVALID_PTN;
- ptn = mmc_ptn_offset((unsigned char *) arg);
- if (ptn == 0) {
+ index = partition_get_index(arg);
+ ptn = partition_get_offset(index);
+ if(ptn == 0) {
fastboot_fail("partition table doesn't exist");
return;
}
-
/* Simple inefficient version of erase. Just writing
0 in first block */
if (mmc_write(ptn , 512, (unsigned int *)out)) {
@@ -551,6 +557,7 @@
{
unsigned long long ptn = 0;
unsigned long long size = 0;
+ int index = INVALID_PTN;
if (!strcmp(arg, "partition"))
{
@@ -562,7 +569,8 @@
}
else
{
- ptn = mmc_ptn_offset((unsigned char *) arg);
+ index = partition_get_index(arg);
+ ptn = partition_get_offset(index);
if(ptn == 0) {
fastboot_fail("partition table doesn't exist");
return;
@@ -575,7 +583,7 @@
}
}
- size = mmc_ptn_size((unsigned char *) arg);
+ size = partition_get_size(index);
if (ROUND_TO_PAGE(sz,511) > size) {
fastboot_fail("size too large");
return;
@@ -599,9 +607,11 @@
chunk_header_t *chunk_header;
uint32_t total_blocks = 0;
unsigned long long ptn = 0;
+ int index = INVALID_PTN;
- ptn = mmc_ptn_offset((unsigned char *) arg);
- if (ptn == 0) {
+ index = partition_get_index(arg);
+ ptn = partition_get_offset(index);
+ if(ptn == 0) {
fastboot_fail("partition table doesn't exist");
return;
}
@@ -919,7 +929,7 @@
fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
fastboot_publish("product", TARGET(BOARD));
fastboot_publish("kernel", "lk");
- mmc_dump_partition_info();
+ partition_dump();
sz = target_get_max_flash_size();
fastboot_init(target_get_scratch_address(), sz);
udc_start();
diff --git a/app/aboot/recovery.c b/app/aboot/recovery.c
index 7b9141c..2ff6804 100644
--- a/app/aboot/recovery.c
+++ b/app/aboot/recovery.c
@@ -37,6 +37,7 @@
#include <lib/ptable.h>
#include <dev/keys.h>
#include <platform.h>
+#include <partition_parser.h>
#include <mmc.h>
#include "recovery.h"
@@ -380,8 +381,10 @@
unsigned long long ptn = 0;
unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
unsigned char data[size];
+ int index = INVALID_PTN;
- ptn = mmc_ptn_offset((unsigned char *) ptn_name);
+ index = partition_get_index((unsigned char *) ptn_name);
+ ptn = partition_get_offset(index);
if(ptn == 0) {
dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
return -1;
@@ -400,8 +403,10 @@
unsigned long long ptn = 0;
unsigned int size = ROUND_TO_PAGE(sizeof(*in),511);
unsigned char data[size];
+ int index = INVALID_PTN;
- ptn = mmc_ptn_offset((unsigned char *) ptn_name);
+ index = partition_get_index((unsigned char *) ptn_name);
+ ptn = partition_get_offset(index);
if(ptn == 0) {
dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
return -1;
diff --git a/app/pcitests/pci_tests.c b/app/pcitests/pci_tests.c
new file mode 100644
index 0000000..86d2b67
--- /dev/null
+++ b/app/pcitests/pci_tests.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <app.h>
+#include <debug.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <compiler.h>
+#include <platform.h>
+#include <dev/pci.h>
+
+#if defined(WITH_LIB_CONSOLE)
+#include <lib/console.h>
+
+/*
+ * enumerates pci devices
+ */
+static void pci_list(void)
+{
+ pci_location_t state;
+ uint16_t device_id, vendor_id;
+ uint8_t header_type;
+ int busses = 0, devices = 0, lines = 0, devfn, ret;
+ char c;
+
+ printf("Scanning...\n");
+
+ for (state.bus = 0; state.bus <= pci_get_last_bus(); state.bus++) {
+ busses++;
+
+ for (devfn = 0; devfn < 256; devfn++) {
+ state.dev_fn = devfn;
+
+ ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ if (vendor_id != 0xffff) {
+ printf("%02x:%02x vendor_id=%04x device_id=%04x, header_type=%02x\n", state.bus, state.dev_fn,
+ vendor_id, device_id, header_type);
+ devices++;
+ lines++;
+ }
+
+ if (~header_type & PCI_HEADER_TYPE_MULTI_FN) {
+ // this is not a multi-function device, so advance to the next device
+ devfn |= 7;
+ }
+
+ if (lines == 23) {
+ printf("... press any key to continue, q to quit ...");
+ while(getc(&c) < 0);
+ printf("\n");
+ lines = 0;
+
+ if (c == 'q' || c == 'Q') goto quit;
+ }
+ }
+ }
+
+ printf("... done. Scanned %d busses, %d device/functions\n", busses, devices);
+quit:
+ return;
+
+error:
+ printf("Error while reading PCI config space: %02x\n", ret);
+}
+
+/*
+ * a somewhat fugly pci config space examine/modify command. this should probably
+ * be broken up a bit.
+ */
+static int pci_config(int argc, const cmd_args *argv)
+{
+ pci_location_t loc;
+ pci_config_t config;
+ uint32_t offset;
+ unsigned int i;
+ int ret;
+
+ if (argc < 5) {
+ return -1;
+ }
+
+ if (!strcmp(argv[2].str, "dump")) {
+ loc.bus = atoui(argv[3].str);
+ loc.dev_fn = atoui(argv[4].str);
+
+ for (i=0; i < sizeof(pci_config_t); i++) {
+ ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+ }
+
+ printf("Device at %02x:%02x vendor id=%04x device id=%04x\n", loc.bus,
+ loc.dev_fn, config.vendor_id, config.device_id);
+ printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n",
+ config.command, config.status, config.program_interface,
+ config.sub_class, config.base_class);
+
+ for (i=0; i < 6; i+=2) {
+ printf("bar%d=%08x bar%d=%08x\n", i, config.base_addresses[i],
+ i+1, config.base_addresses[i+1]);
+ }
+ } else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) {
+ if (argc != 6) {
+ return -1;
+ }
+
+ loc.bus = atoui(argv[3].str);
+ loc.dev_fn = atoui(argv[4].str);
+ offset = atoui(argv[5].str);
+
+ switch (argv[2].str[1]) {
+ case 'b': {
+ uint8_t value;
+ ret = pci_read_config_byte(&loc, offset, &value);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
+ }
+ break;
+
+ case 'h': {
+ uint16_t value;
+ ret = pci_read_config_half(&loc, offset, &value);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
+ }
+ break;
+
+ case 'w': {
+ uint32_t value;
+ ret = pci_read_config_word(&loc, offset, &value);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
+ }
+ break;
+ }
+ } else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) {
+ if (argc != 7) {
+ return -1;
+ }
+
+ loc.bus = atoui(argv[3].str);
+ loc.dev_fn = atoui(argv[4].str);
+ offset = atoui(argv[5].str);
+
+ switch (argv[2].str[1]) {
+ case 'b': {
+ uint8_t value = atoui(argv[6].str);
+ ret = pci_write_config_byte(&loc, offset, value);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
+ }
+ break;
+
+ case 'h': {
+ uint16_t value = atoui(argv[6].str);
+ ret = pci_write_config_half(&loc, offset, value);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
+ }
+ break;
+
+ case 'w': {
+ uint32_t value = atoui(argv[6].str);
+ ret = pci_write_config_word(&loc, offset, value);
+ if (ret != _PCI_SUCCESSFUL) goto error;
+
+ printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
+ }
+ break;
+ }
+ } else {
+ return -1;
+ }
+
+ return 0;
+
+error:
+ printf("Error while reading PCI config space: %02x\n", ret);
+ return -2;
+}
+
+static int pci_cmd(int argc, const cmd_args *argv)
+{
+ if (argc < 2) {
+ printf("pci commands:\n");
+usage:
+ printf("%s list\n", argv[0].str);
+ printf("%s config dump <bus> <devfn>\n", argv[0].str);
+ printf("%s config <rb|rh|rw> <bus> <devfn> <offset>\n", argv[0].str);
+ printf("%s config <mb|mh|mw> <bus> <devfn> <offset> <value>\n", argv[0].str);
+ goto out;
+ }
+
+ if (!strcmp(argv[1].str, "list")) {
+ pci_list();
+ } else if (!strcmp(argv[1].str, "config")) {
+ if (pci_config(argc, argv)) {
+ goto usage;
+ }
+ } else {
+ goto usage;
+ }
+
+out:
+ return 0;
+}
+
+STATIC_COMMAND_START
+{ "pci", "pci toolbox", &pci_cmd },
+STATIC_COMMAND_END(pcitests);
+
+#endif
+
+APP_START(pcitests)
+APP_END
+
diff --git a/app/pcitests/rules.mk b/app/pcitests/rules.mk
new file mode 100644
index 0000000..a72aa49
--- /dev/null
+++ b/app/pcitests/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+#INCLUDES += -I$(LOCAL_DIR)/include
+
+OBJS += \
+ $(LOCAL_DIR)/pci_tests.o
diff --git a/app/tests/tests.c b/app/tests/tests.c
index 1a8130b..1a41f6f 100644
--- a/app/tests/tests.c
+++ b/app/tests/tests.c
@@ -29,8 +29,8 @@
#include <lib/console.h>
STATIC_COMMAND_START
- { "printf_tests", NULL, (console_cmd)&printf_tests },
- { "thread_tests", NULL, (console_cmd)&thread_tests },
+STATIC_COMMAND("printf_tests", NULL, (console_cmd)&printf_tests)
+STATIC_COMMAND("thread_tests", NULL, (console_cmd)&thread_tests)
STATIC_COMMAND_END(tests);
#endif
diff --git a/app/tests/thread_tests.c b/app/tests/thread_tests.c
index acbdfbd..908abc7 100644
--- a/app/tests/thread_tests.c
+++ b/app/tests/thread_tests.c
@@ -221,11 +221,11 @@
event_wait(&context_switch_event);
- uint count = debug_cycle_count();
+ uint count = arch_cycle_count();
for (i = 0; i < iter; i++) {
thread_yield();
}
- total_count += debug_cycle_count() - count;
+ total_count += arch_cycle_count() - count;
thread_sleep(1000);
printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n",
total_count, iter, total_count / iter, total_count / iter / thread_count);
diff --git a/arch/arm/arch.c b/arch/arm/arch.c
index 37b557c..7a5f85b 100644
--- a/arch/arm/arch.c
+++ b/arch/arm/arch.c
@@ -64,6 +64,19 @@
val = (1<<30);
__asm__ volatile("mcr p10, 7, %0, c8, c0, 0" :: "r" (val));
#endif
+
+#if ARM_CPU_CORTEX_A8
+ /* enable the cycle count register */
+ uint32_t en;
+ __asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en));
+ en &= ~(1<<3); /* cycle count every cycle */
+ en |= 1; /* enable all performance counters */
+ __asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en));
+
+ /* enable cycle counter */
+ en = (1<<31);
+ __asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en));
+#endif
}
void arch_init(void)
diff --git a/arch/arm/cache-ops.S b/arch/arm/cache-ops.S
index 8a545dc..b169a77 100644
--- a/arch/arm/cache-ops.S
+++ b/arch/arm/cache-ops.S
@@ -342,6 +342,17 @@
mcr p15, 0, r0, c7, c10, 4 // data sync barrier (formerly drain write buffer)
bx lr
+
+ /* void arch_sync_cache_range(addr_t start, size_t len); */
+FUNCTION(arch_sync_cache_range)
+ push { r14 }
+ bl arch_clean_cache_range
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0 // invalidate icache to PoU
+
+ pop { pc }
+
#else
#error unhandled cpu
#endif
@@ -362,5 +373,8 @@
FUNCTION(arch_clean_invalidate_cache_range)
bx lr
+FUNCTION(arch_sync_cache_range)
+ bx lr
+
#endif // ARM_WITH_CACHE
diff --git a/arch/arm/crt0.S b/arch/arm/crt0.S
index 68dbc67..ce823c1 100644
--- a/arch/arm/crt0.S
+++ b/arch/arm/crt0.S
@@ -24,7 +24,7 @@
#define DSB .byte 0x4f, 0xf0, 0x7f, 0xf5
#define ISB .byte 0x6f, 0xf0, 0x7f, 0xf5
-.text
+.section ".text.boot"
.globl _start
_start:
b reset
@@ -187,3 +187,14 @@
abort_stack:
.skip 1024
abort_stack_top:
+
+.rodata:
+.align 2
+
+/* define the heap end as read-only data containing the end defined in the
+ * linker script. other archs that use dynamic memory length discovery can make
+ * this read-write and update it during init.
+ */
+.global _heap_end
+_heap_end:
+ .int _end_of_ram
diff --git a/arch/arm/ops.S b/arch/arm/ops.S
index 96b7445..c9660e7 100644
--- a/arch/arm/ops.S
+++ b/arch/arm/ops.S
@@ -221,3 +221,15 @@
mcr p15, 0, r0, c7, c10, 4
#endif
bx lr
+
+/* uint32_t arm_read_cycle_count(void); */
+FUNCTION(arm_read_cycle_count)
+
+/* uint32_t arch_cycle_count(void); */
+FUNCTION(arch_cycle_count)
+#if ARM_CPU_CORTEX_A8
+ mrc p15, 0, r0, c9, c13, 0
+#else
+ mov r0, #0
+#endif
+ bx lr
diff --git a/arch/arm/system-onesegment.ld b/arch/arm/system-onesegment.ld
index 9f0e7fc..f2c62ac 100644
--- a/arch/arm/system-onesegment.ld
+++ b/arch/arm/system-onesegment.ld
@@ -6,6 +6,10 @@
{
. = %MEMBASE%;
+ /* text/read-only data */
+ .text.boot : { *(.text.boot) }
+ .text : { *(.text .text.* .glue_7* .gnu.linkonce.t.*) } =0x9090
+
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
@@ -33,9 +37,6 @@
.init : { *(.init) } =0x9090
.plt : { *(.plt) }
- /* text/read-only data */
- .text : { *(.text .text.* .glue_7* .gnu.linkonce.t.*) } =0x9090
-
.rodata : {
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(4);
diff --git a/arch/arm/system-twosegment.ld b/arch/arm/system-twosegment.ld
index 3a1c04c..d636296 100644
--- a/arch/arm/system-twosegment.ld
+++ b/arch/arm/system-twosegment.ld
@@ -6,6 +6,10 @@
{
. = %ROMBASE%;
+ /* text/read-only data */
+ .text.boot : { *(.text.boot) }
+ .text : { *(.text .text.* .glue_7* .gnu.linkonce.t.*) } =0x9090
+
.interp : { *(.interp) }
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
@@ -33,9 +37,6 @@
.init : { *(.init) } =0x9090
.plt : { *(.plt) }
- /* text/read-only data */
- .text : { *(.text .text.* .glue_7* .gnu.linkonce.t.*) } =0x9090
-
.rodata : {
*(.rodata .rodata.* .gnu.linkonce.r.*)
. = ALIGN(4);
diff --git a/arch/x86/arch.c b/arch/x86/arch.c
new file mode 100644
index 0000000..bb6a17b
--- /dev/null
+++ b/arch/x86/arch.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <arch.h>
+#include <arch/ops.h>
+#include <arch/x86.h>
+#include <arch/x86/mmu.h>
+#include <arch/x86/descriptor.h>
+#include <platform.h>
+#include <sys/types.h>
+#include <string.h>
+
+static tss_t system_tss;
+
+void arch_early_init(void)
+{
+ x86_mmu_init();
+
+ platform_init_mmu_mappings();
+
+ /* enable caches here for now */
+ clear_in_cr0(X86_CR0_NW | X86_CR0_CD);
+
+ memset(&system_tss, 0, sizeof(tss_t));
+
+ system_tss.esp0 = 0;
+ system_tss.ss0 = DATA_SELECTOR;
+ system_tss.ss1 = 0;
+ system_tss.ss2 = 0;
+ system_tss.eflags = 0x00003002;
+ system_tss.bitmap = offsetof(tss_t, tss_bitmap);
+ system_tss.trace = 1; // trap on hardware task switch
+
+ set_global_desc(TSS_SELECTOR, &system_tss, sizeof(tss_t), 1, 0, 0, SEG_TYPE_TSS, 0, 0);
+
+ x86_ltr(TSS_SELECTOR);
+}
+
+void arch_init(void)
+{
+}
+
+uint32_t arch_cycle_count(void)
+{
+ uint32_t timestamp;
+ rdtscl(timestamp);
+
+ return timestamp;
+}
+
diff --git a/arch/x86/asm.S b/arch/x86/asm.S
new file mode 100644
index 0000000..8916243
--- /dev/null
+++ b/arch/x86/asm.S
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+
diff --git a/arch/x86/cache-ops.S b/arch/x86/cache-ops.S
new file mode 100644
index 0000000..9ad7c71
--- /dev/null
+++ b/arch/x86/cache-ops.S
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+#include <arch/ops.h>
+#include <arch/defines.h>
+
+.text
+
+/* stubs */
+
+FUNCTION(arch_disable_cache)
+ ret
+
+FUNCTION(arch_enable_cache)
+ ret
+
+FUNCTION(arch_clean_cache_range)
+ ret
+
+FUNCTION(arch_clean_invalidate_cache_range)
+ ret
+
diff --git a/arch/x86/cache.c b/arch/x86/cache.c
new file mode 100644
index 0000000..b00d6cc
--- /dev/null
+++ b/arch/x86/cache.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
diff --git a/arch/x86/compile.mk b/arch/x86/compile.mk
new file mode 100644
index 0000000..271db17
--- /dev/null
+++ b/arch/x86/compile.mk
@@ -0,0 +1,16 @@
+
+$(BUILDDIR)/%.o: %.c $(SRCDEPS)
+ @$(MKDIR)
+ @echo compiling $<
+ $(NOECHO)$(CC) $(CFLAGS) --std=c99 $(INCLUDES) -c $< -MD -MT $@ -MF $(@:%o=%d) -o $@
+
+$(BUILDDIR)/%.o: %.cpp $(SRCDEPS)
+ @$(MKDIR)
+ @echo compiling $<
+ $(NOECHO)$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c $< -MD -MT $@ -MF $(@:%o=%d) -o $@
+
+$(BUILDDIR)/%.o: %.S $(SRCDEPS)
+ @$(MKDIR)
+ @echo compiling $<
+ $(NOECHO)$(CC) $(CFLAGS) $(ASMFLAGS) $(INCLUDES) -c $< -MD -MT $@ -MF $(@:%o=%d) -o $@
+
diff --git a/arch/x86/crt0.S b/arch/x86/crt0.S
new file mode 100644
index 0000000..9cc9ab0
--- /dev/null
+++ b/arch/x86/crt0.S
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* The magic number for the Multiboot header. */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* The flags for the Multiboot header. */
+#if defined(__ELF__) && 0
+#define MULTIBOOT_HEADER_FLAGS 0x00000002
+#else
+#define MULTIBOOT_HEADER_FLAGS 0x00010002
+#endif
+
+/* The magic number passed by a Multiboot-compliant boot loader. */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+#define NUM_INT 0x31
+#define NUM_EXC 0x14
+
+.text
+.global _start
+_start:
+ jmp real_start
+
+.align 4
+
+multiboot_header:
+ /* magic */
+ .int MULTIBOOT_HEADER_MAGIC
+ /* flags */
+ .int MULTIBOOT_HEADER_FLAGS
+ /* checksum */
+ .int -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
+
+#if !defined(__ELF__) || 1
+ /* header_addr */
+ .int multiboot_header
+ /* load_addr */
+ .int _start
+ /* load_end_addr */
+ .int __bss_start
+ /* bss_end_addr */
+ .int __bss_end
+ /* entry_addr */
+ .int real_start
+#endif
+
+real_start:
+ cmpl $MULTIBOOT_BOOTLOADER_MAGIC, %eax
+ jne 0f
+ movl %ebx, (_multiboot_info)
+0:
+ /* setup isr stub descriptors in the idt */
+ movl $_isr, %esi
+ movl $_idt, %edi
+ movl $NUM_INT, %ecx
+
+.Lloop:
+ movl %esi, %ebx
+ movw %bx, (%edi) /* low word in IDT(n).low */
+ shrl $16, %ebx
+ movw %bx, 6(%edi) /* high word in IDT(n).high */
+
+ addl $isr_stub_len, %esi/* index the next ISR stub */
+ addl $8, %edi /* index the next IDT entry */
+
+ loop .Lloop
+
+ lidt _idtr
+ xorl %eax, %eax
+ movl %eax, %cr3
+
+ lgdt _gdtr
+
+ movw $datasel, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %ss
+ movw %ax, %gs
+ movw %ax, %ss
+
+ movl $_kstack, %esp
+
+ /* zero the bss section */
+ movl $__bss_start, %edi /* starting address of the bss */
+ movl $__bss_end, %ecx /* find the length of the bss in bytes */
+ subl %edi, %ecx
+ shrl $2, %ecx /* convert to 32 bit words, since the bss is aligned anyway */
+2:
+ movl $0, (%edi)
+ addl $4, %edi
+ loop 2b
+
+ /* call the main module */
+ call kmain
+
+0: /* just sit around waiting for interrupts */
+ hlt /* interrupts will unhalt the processor */
+ pause
+ jmp 0b /* so jump back to halt to conserve power */
+
+/* interrupt service routine stubs */
+_isr:
+
+.set i, 0
+.rept NUM_INT
+
+.set isr_stub_start, .
+
+.if i == 8 || (i >= 10 && i <= 14) || i == 17
+ nop /* error code pushed by exception */
+ nop /* 2 nops are the same length as push byte */
+ pushl $i /* interrupt number */
+ jmp interrupt_common
+.else
+ pushl $0 /* fill in error code in iframe */
+ pushl $i /* interrupt number */
+ jmp interrupt_common
+.endif
+
+/* figure out the length of a single isr stub (usually 6 or 9 bytes) */
+.set isr_stub_len, . - isr_stub_start
+
+.set i, i + 1
+.endr
+
+/* annoying, but force AS to use the same (longer) encoding of jmp for all of the stubs */
+.fill 256
+
+interrupt_common:
+ pushl %gs /* save segment registers */
+ pushl %fs
+ pushl %es
+ pushl %ds
+ pusha /* save general purpose registers */
+ movl $datasel, %eax /* put known good value in segment registers */
+ movl %eax, %gs
+ movl %eax, %fs
+ movl %eax, %es
+ movl %eax, %ds
+ movl %esp, %eax /* store stack switch pivot. push esp has errata on some cpus, so use mov/push */
+ pushl %eax
+ movl %esp, %eax /* store pointer to iframe, using same method */
+ pushl %eax
+
+ incl critical_section_count
+
+ call platform_irq
+
+ cmpl $0,%eax
+ je 0f
+ call thread_preempt
+
+0:
+ decl critical_section_count
+
+ popl %eax /* drop pointer to iframe */
+ popl %eax /* restore task_esp, stack switch can occur here if task_esp is modified */
+ movl %eax, %esp
+ popa /* restore general purpose registers */
+ popl %ds /* restore segment registers */
+ popl %es
+ popl %fs
+ popl %gs
+ addl $8, %esp /* drop exception number and error code */
+ iret
+
+.data
+.align 4
+
+/* define the heap end as read-write data containing the default end of the
+ * heap. dynamic memory length discovery can update this value during init.
+ * other archs can define this statically based on the memory layout of the
+ * platform.
+ */
+.global _heap_end
+_heap_end:
+ .int 4096*1024 /* default to 4MB total */
+
+.global _multiboot_info
+_multiboot_info:
+ .int 0
+
+.global _gdtr
+_gdtr:
+ .short _gdt_end - _gdt - 1
+ .int _gdt
+
+.global _gdt
+_gdt:
+ .int 0
+ .int 0
+
+/* ring 0 descriptors */
+.set codesel, . - _gdt
+_code_gde:
+ .short 0xffff /* limit 15:00 */
+ .short 0x0000 /* base 15:00 */
+ .byte 0x00 /* base 23:16 */
+ .byte 0b10011010 /* P(1) DPL(00) S(1) 1 C(0) R(1) A(0) */
+ .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
+ .byte 0x0 /* base 31:24 */
+
+.set datasel, . - _gdt
+_data_gde:
+ .short 0xffff /* limit 15:00 */
+ .short 0x0000 /* base 15:00 */
+ .byte 0x00 /* base 23:16 */
+ .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
+ .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
+ .byte 0x0 /* base 31:24 */
+
+.set videosel, . - _gdt
+_video_gde:
+ .short 0xffff /* limit 15:00 */
+ .short 0x8000 /* base 15:00 */
+ .byte 0x0b /* base 23:16 */
+ .byte 0b10010010 /* P(1) DPL(00) S(1) 0 E(0) W(1) A(0) */
+ .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
+ .byte 0x0 /* base 31:24 */
+
+.if 1
+/* ring 3 descriptors */
+.set user_codesel, . - _gdt
+_user_code_gde:
+ .short 0xffff /* limit 15:00 */
+ .short 0x0000 /* base 15:00 */
+ .byte 0x00 /* base 23:16 */
+ .byte 0b11111010 /* P(1) DPL(11) S(1) 1 C(0) R(1) A(0) */
+ .byte 0b11001111 /* G(1) D(1) 0 0 limit 19:16 */
+ .byte 0x0 /* base 31:24 */
+
+.set user_datasel, . - _gdt
+_user_data_gde:
+ .short 0xffff /* limit 15:00 */
+ .short 0x0000 /* base 15:00 */
+ .byte 0x00 /* base 23:16 */
+ .byte 0b11110010 /* P(1) DPL(11) S(1) 0 E(0) W(1) A(0) */
+ .byte 0b11001111 /* G(1) B(1) 0 0 limit 19:16 */
+ .byte 0x0 /* base 31:24 */
+.endif
+
+/* TSS descriptor */
+.if 1
+.set tsssel, . - _gdt
+_tss_gde:
+ .short 0 /* limit 15:00 */
+ .short 0 /* base 15:00 */
+ .byte 0 /* base 23:16 */
+ .byte 0xe9 /* P(1) DPL(11) 0 10 B(0) 1 */
+ .byte 0x00 /* G(0) 0 0 AVL(0) limit 19:16 */
+ .short 0 /* base 31:24 */
+.endif
+
+.global _gdt_end
+_gdt_end:
+
+.global _idtr
+_idtr:
+ .short _idt_end - _idt - 1 /* IDT limit */
+ .int _idt
+
+/* interrupt descriptor table (IDT) */
+.global _idt
+_idt:
+
+.set i, 0
+.rept NUM_INT-1
+ .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
+ .short codesel /* selector */
+ .byte 0
+ .byte 0x8e /* present, ring 0, 32-bit interrupt gate */
+ .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
+
+.set i, i + 1
+.endr
+
+/* syscall int (ring 3) */
+_idt30:
+ .short 0 /* low 16 bits of ISR offset (_isr#i & 0FFFFh) */
+ .short codesel /* selector */
+ .byte 0
+ .byte 0xee /* present, ring 3, 32-bit interrupt gate */
+ .short 0 /* high 16 bits of ISR offset (_isr#i / 65536) */
+
+.global _idt_end
+_idt_end:
+
+.bss
+.align 4096
+
+.global _kstack
+.fill 4096
+_kstack:
diff --git a/arch/x86/descriptor.c b/arch/x86/descriptor.c
new file mode 100644
index 0000000..27ee37e
--- /dev/null
+++ b/arch/x86/descriptor.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <compiler.h>
+#include <arch/x86/descriptor.h>
+
+/* not the best way to do this, but easy for now */
+typedef struct {
+ uint16_t limit_15_0;
+ uint16_t base_15_0;
+ uint8_t base_23_16;
+
+ uint8_t type : 4;
+ uint8_t s : 1;
+ uint8_t dpl : 2;
+ uint8_t p : 1;
+
+ uint8_t limit_19_16 : 4;
+ uint8_t avl : 1;
+ uint8_t reserved_0 : 1;
+ uint8_t d_b : 1;
+ uint8_t g : 1;
+
+ uint8_t base_31_24;
+} __PACKED seg_desc_t;
+
+extern seg_desc_t _gdt[];
+
+void set_global_desc(seg_sel_t sel, void *base, uint32_t limit,
+ uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits)
+{
+ // convert selector into index
+ uint16_t index = sel >> 3;
+
+ _gdt[index].limit_15_0 = limit & 0x0000ffff;
+ _gdt[index].limit_19_16 = (limit & 0x000f0000) >> 16;
+
+ _gdt[index].base_15_0 = ((uint32_t) base) & 0x0000ffff;
+ _gdt[index].base_23_16 = (((uint32_t) base) & 0x00ff0000) >> 16;
+ _gdt[index].base_31_24 = ((uint32_t) base) >> 24;
+
+ _gdt[index].type = type & 0x0f; // segment type
+ _gdt[index].p = present != 0; // present
+ _gdt[index].dpl = ring & 0x03; // descriptor privilege level
+ _gdt[index].g = gran != 0; // granularity
+ _gdt[index].s = sys != 0; // system / non-system
+ _gdt[index].d_b = bits != 0; // 16 / 32 bit
+}
diff --git a/arch/x86/faults.c b/arch/x86/faults.c
new file mode 100644
index 0000000..3d4c8d2
--- /dev/null
+++ b/arch/x86/faults.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <arch/x86.h>
+#include <kernel/thread.h>
+
+static void dump_fault_frame(struct x86_iframe *frame)
+{
+ dprintf(CRITICAL, " CS: %04x EIP: %08x EFL: %08x CR2: %08x\n",
+ frame->cs, frame->eip, frame->eflags, x86_get_cr2());
+ dprintf(CRITICAL, "EAX: %08x ECX: %08x EDX: %08x EBX: %08x\n",
+ frame->eax, frame->ecx, frame->edx, frame->ebx);
+ dprintf(CRITICAL, "ESP: %08x EBP: %08x ESI: %08x EDI: %08x\n",
+ frame->esp, frame->ebp, frame->esi, frame->edi);
+ dprintf(CRITICAL, " DS: %04x ES: %04x FS: %04x GS: %04x\n",
+ frame->ds, frame->es, frame->fs, frame->gs);
+
+ // dump the bottom of the current stack
+ addr_t stack = (addr_t) frame; //(addr_t) (((uint32_t *) frame) + (sizeof(struct x86_iframe) / sizeof(uint32_t) - 1));
+
+ if (stack != 0) {
+ dprintf(CRITICAL, "bottom of stack at 0x%08x:\n", (unsigned int)stack);
+ hexdump((void *)stack, 192);
+ }
+}
+
+static void exception_die(struct x86_iframe *frame, const char *msg)
+{
+ inc_critical_section();
+ dprintf(CRITICAL, msg);
+ dump_fault_frame(frame);
+
+ for (;;) {
+ x86_cli();
+ x86_hlt();
+ }
+}
+
+void x86_syscall_handler(struct x86_iframe *frame)
+{
+ exception_die(frame, "unhandled syscall, halting\n");
+}
+
+void x86_gpf_handler(struct x86_iframe *frame)
+{
+ exception_die(frame, "unhandled gpf, halting\n");
+}
+
+void x86_invop_handler(struct x86_iframe *frame)
+{
+ exception_die(frame, "unhandled invalid op, halting\n");
+}
+
+void x86_unhandled_exception(struct x86_iframe *frame)
+{
+ exception_die(frame, "unhandled exception, halting\n");
+}
diff --git a/arch/x86/include/arch/arch_thread.h b/arch/x86/include/arch/arch_thread.h
new file mode 100644
index 0000000..9347bcd
--- /dev/null
+++ b/arch/x86/include/arch/arch_thread.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __X86_ARCH_THREAD_H
+#define __X86_ARCH_THREAD_H
+
+struct arch_thread {
+ vaddr_t esp;
+
+ // TODO: fpu context
+};
+
+#endif
+
diff --git a/arch/x86/include/arch/defines.h b/arch/x86/include/arch/defines.h
new file mode 100644
index 0000000..814fcc9
--- /dev/null
+++ b/arch/x86/include/arch/defines.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __ARCH_CPU_H
+#define __ARCH_CPU_H
+
+#define PAGE_SIZE 4096
+
+// TODO: define to resolve to platform setup discovered value
+#define CACHE_LINE 32
+
+#endif
+
diff --git a/arch/x86/include/arch/x86.h b/arch/x86/include/arch/x86.h
new file mode 100644
index 0000000..4cf65d9
--- /dev/null
+++ b/arch/x86/include/arch/x86.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __ARCH_X86_H
+#define __ARCH_X86_H
+
+#include <compiler.h>
+#include <sys/types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void x86_mmu_init(void);
+
+struct x86_iframe {
+ uint32_t pivot; // stack switch pivot
+ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pushed by common handler using pusha
+ uint32_t ds, es, fs, gs; // pushed by common handler
+ uint32_t vector; // pushed by stub
+ uint32_t err_code; // pushed by interrupt or stub
+ uint32_t eip, cs, eflags; // pushed by interrupt
+ uint32_t user_esp, user_ss; // pushed by interrupt if priv change occurs
+};
+
+/*
+ * x86 TSS structure
+ */
+typedef struct {
+ uint16_t backlink, __blh;
+ uint32_t esp0;
+ uint16_t ss0, __ss0h;
+ uint32_t esp1;
+ uint16_t ss1, __ss1h;
+ uint32_t esp2;
+ uint16_t ss2, __ss2h;
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t eax, ecx, edx, ebx;
+ uint32_t esp, ebp, esi, edi;
+ uint16_t es, __esh;
+ uint16_t cs, __csh;
+ uint16_t ss, __ssh;
+ uint16_t ds, __dsh;
+ uint16_t fs, __fsh;
+ uint16_t gs, __gsh;
+ uint16_t ldt, __ldth;
+ uint16_t trace, bitmap;
+
+ uint8_t tss_bitmap[8192];
+} __PACKED tss_t;
+
+#define X86_CR0_PE 0x00000001 /* protected mode enable */
+#define X86_CR0_MP 0x00000002 /* monitor coprocessor */
+#define X86_CR0_EM 0x00000004 /* emulation */
+#define X86_CR0_TS 0x00000008 /* task switched */
+#define X86_CR0_WP 0x00010000 /* supervisor write protect */
+#define X86_CR0_NW 0x20000000 /* not write-through */
+#define X86_CR0_CD 0x40000000 /* cache disable */
+#define X86_CR0_PG 0x80000000 /* enable paging */
+
+static inline void set_in_cr0(uint32_t mask) {
+ __asm__ __volatile__ (
+ "movl %%cr0,%%eax \n\t"
+ "orl %0,%%eax \n\t"
+ "movl %%eax,%%cr0 \n\t"
+ : : "irg" (mask)
+ :"ax");
+}
+
+static inline void clear_in_cr0(uint32_t mask) {
+ __asm__ __volatile__ (
+ "movl %%cr0, %%eax \n\t"
+ "andl %0, %%eax \n\t"
+ "movl %%eax, %%cr0 \n\t"
+ : : "irg" (~mask)
+ : "ax");
+}
+
+static inline void x86_clts(void) {__asm__ __volatile__ ("clts"); }
+static inline void x86_hlt(void) {__asm__ __volatile__ ("hlt"); }
+static inline void x86_sti(void) {__asm__ __volatile__ ("sti"); }
+static inline void x86_cli(void) {__asm__ __volatile__ ("cli"); }
+static inline void x86_ltr(uint16_t sel) {
+ __asm__ __volatile__ ("ltr %%ax" :: "a" (sel));
+}
+
+static inline uint32_t x86_get_cr2(void) {
+ uint32_t rv;
+
+ __asm__ __volatile__ (
+ "movl %%cr2, %0"
+ : "=r" (rv)
+ );
+
+ return rv;
+}
+
+#define rdtsc(low,high) \
+ __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+ __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) \
+ __asm__ __volatile__("rdtsc" : "=A" (val))
+
+static inline uint8_t inp(uint16_t _port) {
+ uint8_t rv;
+ __asm__ __volatile__ ("inb %1, %0"
+ : "=a" (rv)
+ : "d" (_port));
+ return(rv);
+}
+
+static inline uint16_t inpw (uint16_t _port) {
+ uint16_t rv;
+ __asm__ __volatile__ ("inw %1, %0"
+ : "=a" (rv)
+ : "d" (_port));
+ return(rv);
+}
+
+static inline uint32_t inpd(uint16_t _port) {
+ uint32_t rv;
+ __asm__ __volatile__ ("inl %1, %0"
+ : "=a" (rv)
+ : "d" (_port));
+ return(rv);
+}
+
+static inline void outp(uint16_t _port, uint8_t _data) {
+ __asm__ __volatile__ ("outb %1, %0"
+ :
+ : "d" (_port),
+ "a" (_data));
+}
+
+static inline void outpw(uint16_t _port, uint16_t _data) {
+ __asm__ __volatile__ ("outw %1, %0"
+ :
+ : "d" (_port),
+ "a" (_data));
+}
+
+static inline void outpd(uint16_t _port, uint32_t _data) {
+ __asm__ __volatile__ ("outl %1, %0"
+ :
+ : "d" (_port),
+ "a" (_data));
+}
+
+static inline void inprep(uint16_t _port, uint8_t *_buffer, uint32_t _reads) {
+ __asm__ __volatile__ ("pushal \n\t"
+ "pushfl \n\t"
+ "cli \n\t"
+ "cld \n\t"
+ "rep insb \n\t"
+ "popfl \n\t"
+ "popal"
+ :
+ : "d" (_port),
+ "D" (_buffer),
+ "c" (_reads));
+}
+
+static inline void outprep(uint16_t _port, uint8_t *_buffer, uint32_t _writes) {
+ __asm__ __volatile__ ("pushal \n\t"
+ "pushfl \n\t"
+ "cli \n\t"
+ "cld \n\t"
+ "rep outsb \n\t"
+ "popfl \n\t"
+ "popal"
+ :
+ : "d" (_port),
+ "S" (_buffer),
+ "c" (_writes));
+}
+
+static inline void inpwrep(uint16_t _port, uint16_t *_buffer, uint32_t _reads) {
+ __asm__ __volatile__ ("pushal \n\t"
+ "pushfl \n\t"
+ "cli \n\t"
+ "cld \n\t"
+ "rep insw \n\t"
+ "popfl \n\t"
+ "popal"
+ :
+ : "d" (_port),
+ "D" (_buffer),
+ "c" (_reads));
+}
+
+static inline void outpwrep(uint16_t _port, uint16_t *_buffer,
+ uint32_t _writes) {
+ __asm__ __volatile__ ("pushal \n\t"
+ "pushfl \n\t"
+ "cli \n\t"
+ "cld \n\t"
+ "rep outsw \n\t"
+ "popfl \n\t"
+ "popal"
+ :
+ : "d" (_port),
+ "S" (_buffer),
+ "c" (_writes));
+}
+
+static inline void inpdrep(uint16_t _port, uint32_t *_buffer,
+ uint32_t _reads) {
+ __asm__ __volatile__ ("pushal \n\t"
+ "pushfl \n\t"
+ "cli \n\t"
+ "cld \n\t"
+ "rep insl \n\t"
+ "popfl \n\t"
+ "popal"
+ :
+ : "d" (_port),
+ "D" (_buffer),
+ "c" (_reads));
+}
+
+static inline void outpdrep(uint16_t _port, uint32_t *_buffer,
+ uint32_t _writes) {
+ __asm__ __volatile__ ("pushal \n\t"
+ "pushfl \n\t"
+ "cli \n\t"
+ "cld \n\t"
+ "rep outsl \n\t"
+ "popfl \n\t"
+ "popal"
+ :
+ : "d" (_port),
+ "S" (_buffer),
+ "c" (_writes));
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/arch/x86/include/arch/x86/descriptor.h b/arch/x86/include/arch/x86/descriptor.h
new file mode 100644
index 0000000..1b2580d
--- /dev/null
+++ b/arch/x86/include/arch/x86/descriptor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __ARCH_DESCRIPTOR_H
+#define __ARCH_DESCRIPTOR_H
+
+#include <sys/types.h>
+
+/*
+ * System Selectors
+ */
+#define CODE_SELECTOR 0x08
+#define DATA_SELECTOR 0x10
+#define VIDEO_SELECTOR 0x18
+#define TSS_SELECTOR 0x30
+
+#define USER_CODE_SELECTOR 0x23
+#define USER_DATA_SELECTOR 0x2b
+
+/*
+ * Descriptor Types
+ */
+#define SEG_TYPE_TSS 0x9
+#define SEG_TYPE_TSS_BUSY 0xb
+#define SEG_TYPE_TASK_GATE 0x5
+#define SEG_TYPE_INT_GATE 0xe // 32 bit
+#define SEG_TYPE_DATA_RW 0x2
+#define SEG_TYPE_CODE_RW 0xa
+
+typedef uint16_t seg_sel_t;
+
+void set_global_desc(seg_sel_t sel, void *base, uint32_t limit,
+ uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits);
+
+#endif
diff --git a/arch/x86/include/arch/x86/mmu.h b/arch/x86/include/arch/x86/mmu.h
new file mode 100644
index 0000000..719710c
--- /dev/null
+++ b/arch/x86/include/arch/x86/mmu.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __ARCH_ARM_MMU_H
+#define __ARCH_ARM_MMU_H
+
+#include <sys/types.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void arm_mmu_init(void);
+
+#define MMU_FLAG_CACHED 0x1
+#define MMU_FLAG_BUFFERED 0x2
+#define MMU_FLAG_READWRITE 0x4
+void arm_mmu_map_section(addr_t paddr, addr_t vaddr, uint flags);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/arch/x86/include/arch/x86/ops.h b/arch/x86/include/arch/x86/ops.h
new file mode 100644
index 0000000..d2bbc24
--- /dev/null
+++ b/arch/x86/include/arch/x86/ops.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __ARCH_X86_OPS_H
+#define __ARHC_X86_OPS_H
+
+#if 0
+#include <compiler.h>
+
+#ifndef ASSEMBLY
+
+// override of some routines
+__GNU_INLINE __ALWAYS_INLINE extern inline void arch_enable_ints(void)
+{
+ __asm__ __volatile__ ("sti");
+}
+
+__GNU_INLINE __ALWAYS_INLINE extern inline void arch_disable_ints(void)
+{
+ __asm__ __volatile__ ("cli");
+}
+
+#endif
+#endif
+
+#endif
+
diff --git a/arch/x86/kernel.ld b/arch/x86/kernel.ld
new file mode 100644
index 0000000..1e3abba
--- /dev/null
+++ b/arch/x86/kernel.ld
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+ENTRY(_start)
+SECTIONS
+{
+ .text 0x0200000 : {
+ *(.text)
+ *(SORT(.text$*))
+ *(.gnu.linkonce.t.*)
+
+ __ctor_list = .;
+ *(SORT(.ctor*))
+ __ctor_end = .;
+ __dtor_list = .;
+ *(SORT(.dtor*))
+ __dtor_end = .;
+
+ . = ALIGN(4096);
+ }
+
+ __data_start = .;
+ .data : { *(.data .data.* .gnu.linkonce.d.*) }
+ .stab : { *(.stab) }
+ .stabst : { *(.stabstr) }
+
+ . = ALIGN(4096);
+ __data_end = .;
+
+ .rdata : {
+ *(.rdata)
+ *(SORT(.rdata$*))
+ *(.rodata*)
+ *(.gnu.linkonce.r.*)
+ __commands_start = .;
+ KEEP (*(.commands))
+ __commands_end = .;
+ . = ALIGN(4);
+ __apps_start = .;
+ KEEP (*(.apps))
+ __apps_end = .;
+
+ . = ALIGN(4096);
+ }
+
+ __bss_start = .;
+ .bss : {
+ *(.bss*)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+
+ . = ALIGN(4096);
+ }
+ __bss_end = .;
+
+ /*. += 0x2000;
+ _kstack = .;
+ . += 0x1000;*/
+
+ _end = .;
+
+ /DISCARD/ : { *(.comment .note .eh_frame) }
+}
diff --git a/arch/x86/mmu.c b/arch/x86/mmu.c
new file mode 100644
index 0000000..6cefe67
--- /dev/null
+++ b/arch/x86/mmu.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <sys/types.h>
+#include <compiler.h>
+#include <arch.h>
+#include <arch/x86.h>
+#include <arch/x86/mmu.h>
+
+void x86_mmu_map_section(addr_t paddr, addr_t vaddr, uint flags)
+{
+ // TODO: stuff
+ //x86_invalidate_tlb();
+}
+
+void x86_mmu_init(void)
+{
+ // TODO: stuff
+}
+
+void arch_disable_mmu(void)
+{
+ // TODO: stuff
+}
diff --git a/arch/x86/ops.S b/arch/x86/ops.S
new file mode 100644
index 0000000..9a97948
--- /dev/null
+++ b/arch/x86/ops.S
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+
+.text
+
+/* void arch_enable_ints(void); */
+FUNCTION(arch_enable_ints)
+ sti
+ ret
+
+/* void arch_disable_ints(void); */
+FUNCTION(arch_disable_ints)
+ cli
+ ret
+
+/* int atomic_swap(int *ptr, int val); */
+FUNCTION(atomic_swap)
+ movl 4(%esp), %edx
+ movl 8(%esp), %eax
+ xchgl %eax, (%edx)
+ ret
+
+/* int atomic_add(int *ptr, int val); */
+FUNCTION(atomic_add)
+ movl 4(%esp), %edx
+ movl 8(%esp), %eax
+ lock
+ xadd %eax, (%edx)
+ ret
+
+/* int atomic_and(int *ptr, int val); */
+FUNCTION(atomic_and)
+ movl 4(%esp), %edx
+ movl (%edx), %eax
+0:
+ movl %eax, %ecx
+ andl 8(%esp), %ecx
+ lock
+ cmpxchgl %ecx, (%edx)
+ jnz 1f /* static prediction: branch forward not taken */
+ ret
+1:
+ jmp 0b
+
+
+/* int atomic_or(int *ptr, int val); */
+FUNCTION(atomic_or)
+movl 4(%esp), %edx
+ movl (%edx), %eax
+0:
+ movl %eax, %ecx
+ orl 8(%esp), %ecx
+ lock
+ cmpxchgl %ecx, (%edx)
+ jnz 1f /* static prediction: branch forward not taken */
+ ret
+1:
+ jmp 0b
+
+/* void arch_idle(); */
+FUNCTION(arch_idle)
+ pushf
+ popl %eax
+ andl $0x200, %eax
+ test %eax, %eax
+ je 1f /* don't halt if local interrupts are disabled */
+ hlt
+1:
+ ret
+
+/* void arch_switch_stacks_and_call(addr_t call, addr_t stack) */
+FUNCTION(arch_switch_stacks_and_call)
+ movl 4(%esp), %eax
+ movl 8(%esp), %edx
+ movl %edx, %esp
+ call *%eax /* perhaps this should be a jmp? it's not used anywhere so I don't know. */
diff --git a/arch/x86/rules.mk b/arch/x86/rules.mk
new file mode 100644
index 0000000..d929cb6
--- /dev/null
+++ b/arch/x86/rules.mk
@@ -0,0 +1,41 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += \
+ -I$(LOCAL_DIR)/include
+
+BOOTOBJS += \
+ $(LOCAL_DIR)/crt0.o
+
+OBJS += \
+ $(LOCAL_DIR)/arch.o \
+ $(LOCAL_DIR)/asm.o \
+ $(LOCAL_DIR)/cache.o \
+ $(LOCAL_DIR)/cache-ops.o \
+ $(LOCAL_DIR)/ops.o \
+ $(LOCAL_DIR)/thread.o \
+ $(LOCAL_DIR)/mmu.o \
+ $(LOCAL_DIR)/faults.o \
+ $(LOCAL_DIR)/descriptor.o
+
+# set the default toolchain to x86 elf and set a #define
+TOOLCHAIN_PREFIX ?= i386-elf-
+
+LIBGCC := $(shell $(TOOLCHAIN_PREFIX)gcc $(CFLAGS) -print-libgcc-file-name)
+#$(info LIBGCC = $(LIBGCC))
+
+cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`"; \
+ then echo "$(2)"; else echo "$(3)"; fi ;)
+
+# disable SSP if the compiler supports it; it will break stuff
+CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+
+# potentially generated files that should be cleaned out with clean make rule
+GENERATED += \
+ $(BUILDDIR)/kernel.ld
+
+# rules for generating the linker scripts
+
+$(BUILDDIR)/kernel.ld: $(LOCAL_DIR)/kernel.ld
+ @echo generating $@
+ @$(MKDIR)
+ $(NOECHO)cp $< $@
diff --git a/arch/x86/thread.c b/arch/x86/thread.c
new file mode 100644
index 0000000..f2c2f84
--- /dev/null
+++ b/arch/x86/thread.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <arch/x86.h>
+#include <arch/x86/descriptor.h>
+
+/*struct context_switch_frame {
+ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
+ uint32_t ds, es, fs, gs;
+ uint32_t eip, cs, eflags;
+};*/
+struct context_switch_frame {
+ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
+ uint32_t eflags;
+ uint32_t eip;
+};
+
+extern void x86_context_switch(addr_t *old_sp, addr_t new_sp);
+
+static void initial_thread_func(void) __NO_RETURN;
+static void initial_thread_func(void)
+{
+ int ret;
+
+// dprintf("initial_thread_func: thread %p calling %p with arg %p\n", current_thread, current_thread->entry, current_thread->arg);
+// dump_thread(current_thread);
+
+ /* exit the implicit critical section we're within */
+ exit_critical_section();
+
+ ret = current_thread->entry(current_thread->arg);
+
+// dprintf("initial_thread_func: thread %p exiting with %d\n", current_thread, ret);
+
+ thread_exit(ret);
+}
+
+void arch_thread_initialize(thread_t *t)
+{
+ // create a default stack frame on the stack
+ vaddr_t stack_top = (vaddr_t)t->stack + t->stack_size;
+
+ // make sure the top of the stack is 8 byte aligned for EABI compliance
+ stack_top = ROUNDDOWN(stack_top, 8);
+
+ struct context_switch_frame *frame = (struct context_switch_frame *)(stack_top);
+ frame--;
+
+ // fill it in
+ memset(frame, 0, sizeof(*frame));
+
+ frame->eip = (vaddr_t) &initial_thread_func;
+ frame->eflags = 0x3002; // IF = 0, NT = 0, IOPL = 3
+ //frame->cs = CODE_SELECTOR;
+ //frame->fs = DATA_SELECTOR;
+ //frame->gs = DATA_SELECTOR;
+ //frame->es = DATA_SELECTOR;
+ //frame->ds = DATA_SELECTOR;
+
+ // set the stack pointer
+ t->arch.esp = (vaddr_t)frame;
+}
+
+void arch_context_switch(thread_t *oldthread, thread_t *newthread)
+{
+ //dprintf(DEBUG, "arch_context_switch: old %p (%s), new %p (%s)\n", oldthread, oldthread->name, newthread, newthread->name);
+
+ __asm__ __volatile__ (
+ "pushl $1f \n\t"
+ "pushf \n\t"
+ "pusha \n\t"
+ "movl %%esp,(%%edx) \n\t"
+ "movl %%eax,%%esp \n\t"
+ "popa \n\t"
+ "popf \n\t"
+ "ret \n\t"
+ "1: \n\t"
+
+ :
+ : "d" (&oldthread->arch.esp), "a" (newthread->arch.esp)
+ );
+
+ /*__asm__ __volatile__ (
+ "pushf \n\t"
+ "pushl %%cs \n\t"
+ "pushl $1f \n\t"
+ "pushl %%gs \n\t"
+ "pushl %%fs \n\t"
+ "pushl %%es \n\t"
+ "pushl %%ds \n\t"
+ "pusha \n\t"
+ "movl %%esp,(%%edx) \n\t"
+ "movl %%eax,%%esp \n\t"
+ "popa \n\t"
+ "popl %%ds \n\t"
+ "popl %%es \n\t"
+ "popl %%fs \n\t"
+ "popl %%gs \n\t"
+ "iret \n\t"
+ "1: "
+ :
+ : "d" (&oldthread->arch.esp), "a" (newthread->arch.esp)
+ );*/
+}
+
diff --git a/include/arch/ops.h b/include/arch/ops.h
index d5bafd0..26d0642 100644
--- a/include/arch/ops.h
+++ b/include/arch/ops.h
@@ -51,6 +51,8 @@
void arch_clean_cache_range(addr_t start, size_t len);
void arch_clean_invalidate_cache_range(addr_t start, size_t len);
+void arch_invalidate_cache_range(addr_t start, size_t len);
+void arch_sync_cache_range(addr_t start, size_t len);
void arch_idle(void);
@@ -58,6 +60,8 @@
void arch_switch_stacks_and_call(addr_t call, addr_t stack) __NO_RETURN;
+uint32_t arch_cycle_count(void);
+
#if defined(__cplusplus)
}
#endif
diff --git a/include/compiler.h b/include/compiler.h
index cd4b243..c3095a8 100644
--- a/include/compiler.h
+++ b/include/compiler.h
@@ -41,6 +41,19 @@
#define __WEAK __attribute__((weak))
#define __GNU_INLINE __attribute__((gnu_inline))
#define __GET_CALLER(x) __builtin_return_address(0)
+#define __GET_FRAME(x) __builtin_frame_address(0)
+
+#define INCBIN(symname, sizename, filename, section) \
+ __asm__ (".section " section "; .align 4; .globl "#symname); \
+ __asm__ (""#symname ":\n.incbin \"" filename "\""); \
+ __asm__ (".section " section "; .align 1;"); \
+ __asm__ (""#symname "_end:"); \
+ __asm__ (".section " section "; .align 4; .globl "#sizename); \
+ __asm__ (""#sizename ": .long "#symname "_end - "#symname " - 1"); \
+ extern unsigned char symname[]; \
+ extern unsigned int sizename
+
+#define INCFILE(symname, sizename, filename) INCBIN(symname, sizename, filename, ".rodata")
/* look for gcc 3.0 and above */
#if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 0)
@@ -106,4 +119,7 @@
#endif
+/* TODO: add type check */
+#define countof(a) (sizeof(a) / sizeof((a)[0]))
+
#endif
diff --git a/include/debug.h b/include/debug.h
index e5ebc19..2944cb7 100644
--- a/include/debug.h
+++ b/include/debug.h
@@ -57,7 +57,7 @@
#define dvprintf(level, x...) do { if ((level) <= DEBUGLEVEL) { _dvprintf(x); } } while (0)
/* input */
-int dgetc(char *c);
+int dgetc(char *c, bool wait);
/* systemwide halts */
void halt(void) __NO_RETURN;
diff --git a/include/dev/display.h b/include/dev/display.h
new file mode 100644
index 0000000..aa0bff6
--- /dev/null
+++ b/include/dev/display.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __DEV_DISPLAY_H
+#define __DEV_DISPLAY_H
+
+#include <sys/types.h>
+#include <lib/gfx.h>
+
+int display_init(void *framebuffer);
+int display_enable(bool enable);
+void display_pre_freq_change(void);
+void display_post_freq_change(void);
+
+struct display_info {
+ void *framebuffer;
+ gfx_format format;
+ uint width;
+ uint height;
+ uint stride;
+
+ // Update function
+ void (*flush)(uint starty, uint endy);
+};
+
+void display_get_info(struct display_info *info);
+
+#endif
+
diff --git a/include/dev/pci.h b/include/dev/pci.h
new file mode 100644
index 0000000..4ba644e
--- /dev/null
+++ b/include/dev/pci.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PCI_H
+#define __PCI_H
+
+#include <sys/types.h>
+#include <compiler.h>
+
+/*
+ * PCI access return codes
+ */
+#define _PCI_SUCCESSFUL 0x00
+#define _PCI_FUNC_NOT_SUPPORTED 0x81
+#define _PCI_BAD_VENDOR_ID 0x83
+#define _PCI_DEVICE_NOT_FOUND 0x86
+#define _PCI_BAD_REGISTER_NUMBER 0x87
+#define _PCI_SET_FAILED 0x88
+#define _PCI_BUFFER_TOO_SMALL 0x89
+
+/*
+ * PCI configuration space offsets
+ */
+#define PCI_CONFIG_VENDOR_ID 0x00
+#define PCI_CONFIG_DEVICE_ID 0x02
+#define PCI_CONFIG_COMMAND 0x04
+#define PCI_CONFIG_STATUS 0x06
+#define PCI_CONFIG_REVISION_ID 0x08
+#define PCI_CONFIG_CLASS_CODE 0x09
+#define PCI_CONFIG_CACHE_LINE_SIZE 0x0c
+#define PCI_CONFIG_LATENCY_TIMER 0x0d
+#define PCI_CONFIG_HEADER_TYPE 0x0e
+#define PCI_CONFIG_BIST 0x0f
+#define PCI_CONFIG_BASE_ADDRESSES 0x10
+#define PCI_CONFIG_CARDBUS_CIS_PTR 0x28
+#define PCI_CONFIG_SUBSYS_VENDOR_ID 0x2c
+#define PCI_CONFIG_SUBSYS_ID 0x2e
+#define PCI_CONFIG_EXP_ROM_ADDRESS 0x30
+#define PCI_CONFIG_CAPABILITIES 0x34
+#define PCI_CONFIG_INTERRUPT_LINE 0x3c
+#define PCI_CONFIG_INTERRUPT_PIN 0x3d
+#define PCI_CONFIG_MIN_GRANT 0x3e
+#define PCI_CONFIG_MAX_LATENCY 0x3f
+
+/*
+ * PCI header type register bits
+ */
+#define PCI_HEADER_TYPE_MASK 0x7f
+#define PCI_HEADER_TYPE_MULTI_FN 0x80
+
+/*
+ * PCI header types
+ */
+#define PCI_HEADER_TYPE_STANDARD 0x00
+#define PCI_HEADER_TYPE_PCI_BRIDGE 0x01
+#define PCI_HEADER_TYPE_CARD_BUS 0x02
+
+/*
+ * PCI command register bits
+ */
+#define PCI_COMMAND_IO_EN 0x0001
+#define PCI_COMMAND_MEM_EN 0x0002
+#define PCI_COMMAND_BUS_MASTER_EN 0x0004
+#define PCI_COMMAND_SPECIAL_EN 0x0008
+#define PCI_COMMAND_MEM_WR_INV_EN 0x0010
+#define PCI_COMMAND_PAL_SNOOP_EN 0x0020
+#define PCI_COMMAND_PERR_RESP_EN 0x0040
+#define PCI_COMMAND_AD_STEP_EN 0x0080
+#define PCI_COMMAND_SERR_EN 0x0100
+#define PCI_COMMAND_FAST_B2B_EN 0x0200
+
+/*
+ * PCI status register bits
+ */
+#define PCI_STATUS_NEW_CAPS 0x0010
+#define PCI_STATUS_66_MHZ 0x0020
+#define PCI_STATUS_FAST_B2B 0x0080
+#define PCI_STATUS_MSTR_PERR 0x0100
+#define PCI_STATUS_DEVSEL_MASK 0x0600
+#define PCI_STATUS_TARG_ABORT_SIG 0x0800
+#define PCI_STATUS_TARG_ABORT_RCV 0x1000
+#define PCI_STATUS_MSTR_ABORT_RCV 0x2000
+#define PCI_STATUS_SERR_SIG 0x4000
+#define PCI_STATUS_PERR 0x8000
+
+typedef struct {
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint16_t command;
+ uint16_t status;
+ uint8_t revision_id_0;
+ uint8_t program_interface;
+ uint8_t sub_class;
+ uint8_t base_class;
+ uint8_t cache_line_size;
+ uint8_t latency_timer;
+ uint8_t header_type;
+ uint8_t bist;
+ uint32_t base_addresses[6];
+ uint32_t cardbus_cis_ptr;
+ uint16_t subsystem_vendor_id;
+ uint16_t subsystem_id;
+ uint32_t expansion_rom_address;
+ uint8_t capabilities_ptr;
+ uint8_t reserved_0[3];
+ uint32_t reserved_1;
+ uint8_t interrupt_line;
+ uint8_t interrupt_pin;
+ uint8_t min_grant;
+ uint8_t max_latency;
+} __PACKED pci_config_t;
+
+/*
+ * PCI address structure
+ */
+typedef struct
+{
+ uint8_t bus;
+ uint8_t dev_fn;
+} pci_location_t;
+
+typedef struct {
+ uint8_t id;
+ uint8_t next;
+} __PACKED pci_capability_t;
+
+typedef struct {
+ uint8_t bus;
+ uint8_t device;
+ uint8_t link_int_a;
+ uint16_t irq_int_a;
+ uint8_t link_int_b;
+ uint16_t irq_int_b;
+ uint8_t link_int_c;
+ uint16_t irq_int_c;
+ uint8_t link_int_d;
+ uint16_t irq_int_d;
+ uint8_t slot;
+ uint8_t reserved;
+} __PACKED irq_routing_entry;
+
+void pci_init(void);
+
+int pci_get_last_bus(void);
+
+int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index);
+int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index);
+
+int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value);
+int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value);
+int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value);
+
+int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value);
+int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value);
+int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value);
+
+int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs);
+int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq);
+
+#endif
diff --git a/include/endian.h b/include/endian.h
index 30623b2..34bef6e 100644
--- a/include/endian.h
+++ b/include/endian.h
@@ -40,6 +40,10 @@
#define BYTE_ORDER LITTLE_ENDIAN
#endif
+#if defined(__i386__) || defined(_X86_)
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
#ifndef BYTE_ORDER
#error "need to get the BYTE_ORDER define from somewhere"
#endif
diff --git a/include/err.h b/include/err.h
index 3b8b401..265c19c 100644
--- a/include/err.h
+++ b/include/err.h
@@ -23,6 +23,8 @@
#ifndef __ERR_H
#define __ERR_H
+#include <sys/types.h> // for status_t
+
#define NO_ERROR 0
#define ERROR -1
#define ERR_NOT_FOUND -2
@@ -37,5 +39,17 @@
#define ERR_OBJECT_DESTROYED -11
#define ERR_NOT_BLOCKED -12
#define ERR_TIMED_OUT -13
+#define ERR_ALREADY_EXISTS -14
+#define ERR_CHANNEL_CLOSED -15
+#define ERR_OFFLINE -16
+#define ERR_NOT_ALLOWED -17
+#define ERR_BAD_PATH -18
+#define ERR_ALREADY_MOUNTED -19
+#define ERR_IO -20
+#define ERR_NOT_DIR -21
+#define ERR_NOT_FILE -22
+#define ERR_RECURSE_TOO_DEEP -23
+#define ERR_NOT_SUPPORTED -24
+#define ERR_TOO_BIG -25
#endif
diff --git a/include/kernel/event.h b/include/kernel/event.h
index 8666737..d0ce7f5 100644
--- a/include/kernel/event.h
+++ b/include/kernel/event.h
@@ -58,6 +58,7 @@
status_t event_wait_timeout(event_t *, time_t); /* wait on the event with a timeout */
status_t event_signal(event_t *, bool reschedule);
status_t event_unsignal(event_t *);
+#define event_initialized(e) ((e)->magic == EVENT_MAGIC)
#endif
diff --git a/include/kernel/thread.h b/include/kernel/thread.h
index 8f76291..6c25712 100644
--- a/include/kernel/thread.h
+++ b/include/kernel/thread.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -205,7 +205,11 @@
status_t thread_unblock_from_wait_queue(thread_t *t, bool reschedule, status_t wait_queue_error);
/* thread level statistics */
+#if DEBUGLEVEL > 1
+#define THREAD_STATS 1
+#else
#define THREAD_STATS 0
+#endif
#if THREAD_STATS
struct thread_stats {
bigtime_t idle_time;
diff --git a/include/kernel/timer.h b/include/kernel/timer.h
index 98332fd..2111d94 100644
--- a/include/kernel/timer.h
+++ b/include/kernel/timer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
diff --git a/include/lib/bcache.h b/include/lib/bcache.h
new file mode 100644
index 0000000..167cfbc
--- /dev/null
+++ b/include/lib/bcache.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2007 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIB_BCACHE_H
+#define __LIB_BCACHE_H
+
+#include <lib/bio.h>
+
+typedef void * bcache_t;
+
+bcache_t bcache_create(bdev_t *dev, size_t block_size, int block_count);
+void bcache_destroy(bcache_t);
+
+int bcache_read_block(bcache_t, void *, uint block);
+
+// get and put a pointer directly to the block
+int bcache_get_block(bcache_t, void **, uint block);
+int bcache_put_block(bcache_t, uint block);
+
+#endif
+
diff --git a/include/lib/bio.h b/include/lib/bio.h
new file mode 100644
index 0000000..a8d145c
--- /dev/null
+++ b/include/lib/bio.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIB_BIO_H
+#define __LIB_BIO_H
+
+#include <sys/types.h>
+#include <list.h>
+
+typedef uint32_t bnum_t;
+
+typedef struct bdev {
+ struct list_node node;
+ volatile int ref;
+
+ /* info about the block device */
+ char *name;
+ off_t size;
+ size_t block_size;
+ bnum_t block_count;
+
+ /* function pointers */
+ ssize_t (*read)(struct bdev *, void *buf, off_t offset, size_t len);
+ ssize_t (*read_block)(struct bdev *, void *buf, bnum_t block, uint count);
+ ssize_t (*write)(struct bdev *, const void *buf, off_t offset, size_t len);
+ ssize_t (*write_block)(struct bdev *, const void *buf, bnum_t block, uint count);
+ ssize_t (*erase)(struct bdev *, off_t offset, size_t len);
+ int (*ioctl)(struct bdev *, int request, void *argp);
+ void (*close)(struct bdev *);
+} bdev_t;
+
+/* user api */
+bdev_t *bio_open(const char *name);
+void bio_close(bdev_t *dev);
+ssize_t bio_read(bdev_t *dev, void *buf, off_t offset, size_t len);
+ssize_t bio_read_block(bdev_t *dev, void *buf, bnum_t block, uint count);
+ssize_t bio_write(bdev_t *dev, const void *buf, off_t offset, size_t len);
+ssize_t bio_write_block(bdev_t *dev, const void *buf, bnum_t block, uint count);
+ssize_t bio_erase(bdev_t *dev, off_t offset, size_t len);
+int bio_ioctl(bdev_t *dev, int request, void *argp);
+
+/* intialize the block device layer */
+void bio_init(void);
+
+/* register a block device */
+void bio_register_device(bdev_t *dev);
+void bio_unregister_device(bdev_t *dev);
+
+/* used during bdev construction */
+void bio_initialize_bdev(bdev_t *dev, const char *name, size_t block_size, bnum_t block_count);
+
+/* debug stuff */
+void bio_dump_devices(void);
+
+/* subdevice support */
+status_t bio_publish_subdevice(const char *parent_dev, const char *subdev, bnum_t startblock, size_t len);
+
+/* memory based block device */
+int create_membdev(const char *name, void *ptr, size_t len);
+
+#endif
+
diff --git a/include/lib/cbuf.h b/include/lib/cbuf.h
new file mode 100644
index 0000000..d71e308
--- /dev/null
+++ b/include/lib/cbuf.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIB_CBUF_H
+#define __LIB_CBUF_H
+
+#include <sys/types.h>
+#include <kernel/event.h>
+
+typedef struct cbuf {
+ uint head;
+ uint tail;
+ uint len_pow2;
+ char *buf;
+ event_t event;
+} cbuf_t;
+
+void cbuf_initialize(cbuf_t *cbuf, size_t len);
+size_t cbuf_read(cbuf_t *cbuf, void *_buf, size_t buflen, bool block);
+size_t cbuf_write(cbuf_t *cbuf, const void *_buf, size_t len, bool canreschedule);
+
+#endif
+
diff --git a/include/lib/font.h b/include/lib/font.h
new file mode 100644
index 0000000..c209c61
--- /dev/null
+++ b/include/lib/font.h
@@ -0,0 +1,12 @@
+#ifndef __LIB_FONT_H
+#define __LIB_FONT_H
+
+#include <lib/gfx.h>
+
+#define FONT_X 6
+#define FONT_Y 12
+
+void font_draw_char(gfx_surface *surface, unsigned char c, int x, int y, uint32_t color);
+
+#endif
+
diff --git a/include/lib/fs.h b/include/lib/fs.h
new file mode 100644
index 0000000..05390cc
--- /dev/null
+++ b/include/lib/fs.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIB_FS_H
+#define __LIB_FS_H
+
+void fs_init(void);
+
+struct file_stat {
+ bool is_dir;
+ off_t size;
+};
+
+typedef void *filecookie;
+typedef void *fscookie;
+
+int fs_mount(const char *path, const char *device);
+int fs_unmount(const char *path);
+
+/* file api */
+int fs_open_file(const char *path, filecookie *fcookie);
+int fs_read_file(filecookie fcookie, void *buf, off_t offset, size_t len);
+int fs_close_file(filecookie fcookie);
+int fs_stat_file(filecookie fcookie, struct file_stat *);
+
+/* convenience routines */
+ssize_t fs_load_file(const char *path, void *ptr, size_t maxlen);
+
+/* walk through a path string, removing duplicate path seperators, flattening . and .. references */
+void fs_normalize_path(char *path);
+
+#endif
+
diff --git a/include/lib/gfx.h b/include/lib/gfx.h
new file mode 100644
index 0000000..2f251e4
--- /dev/null
+++ b/include/lib/gfx.h
@@ -0,0 +1,86 @@
+#ifndef __LIB_GFX_H
+#define __LIB_GFX_H
+
+#include <sys/types.h>
+
+// gfx library
+
+// different graphics formats
+typedef enum {
+ GFX_FORMAT_RGB_565,
+ GFX_FORMAT_ARGB_8888,
+ GFX_FORMAT_RGB_x888,
+
+ GFX_FORMAT_MAX
+} gfx_format;
+
+#define MAX_ALPHA 255
+
+/**
+ * @brief Describe a graphics drawing surface
+ *
+ * The gfx_surface object represents a framebuffer that can be rendered
+ * to. Elements include a pointer to the actual pixel memory, its size, its
+ * layout, and pointers to basic drawing functions.
+ *
+ * @ingroup graphics
+ */
+typedef struct gfx_surface {
+ void *ptr;
+ bool free_on_destroy;
+ gfx_format format;
+ uint width;
+ uint height;
+ uint stride;
+ uint pixelsize;
+ size_t len;
+ uint alpha;
+
+ // function pointers
+ void (*copyrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint x2, uint y2);
+ void (*fillrect)(struct gfx_surface *, uint x, uint y, uint width, uint height, uint color);
+ void (*putpixel)(struct gfx_surface *, uint x, uint y, uint color);
+ void (*flush)(uint starty, uint endy);
+} gfx_surface;
+
+// copy a rect from x,y with width x height to x2, y2
+void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2);
+
+// fill a rect within the surface with a color
+void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color);
+
+// draw a pixel at x, y in the surface
+void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color);
+
+// clear the entire surface with a color
+static inline void gfx_clear(gfx_surface *surface, uint color)
+{
+ surface->fillrect(surface, 0, 0, surface->width, surface->height, color);
+
+ if (surface->flush)
+ surface->flush(0, surface->height-1);
+}
+
+// blend between two surfaces
+void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty);
+
+void gfx_flush(struct gfx_surface *surface);
+
+void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end);
+
+// surface setup
+gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format);
+
+// utility routine to make a surface out of a display info
+struct display_info;
+gfx_surface *gfx_create_surface_from_display(struct display_info *);
+
+// free the surface
+// optionally frees the buffer if the free bit is set
+void gfx_surface_destroy(struct gfx_surface *surface);
+
+// utility routine to fill the display with a little moire pattern
+void gfx_draw_pattern(void);
+
+#endif
+
diff --git a/include/lib/gfxconsole.h b/include/lib/gfxconsole.h
new file mode 100644
index 0000000..4425f50
--- /dev/null
+++ b/include/lib/gfxconsole.h
@@ -0,0 +1,10 @@
+#ifndef __LIB_GFXCONSOLE_H
+#define __LIB_GFXCONSOLE_H
+
+#include <lib/gfx.h>
+
+void gfxconsole_start_on_display(void);
+void gfxconsole_start(gfx_surface *surface);
+
+#endif
+
diff --git a/include/lib/partition.h b/include/lib/partition.h
new file mode 100644
index 0000000..576bc97
--- /dev/null
+++ b/include/lib/partition.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __LIB_PARTITION_H
+#define __LIB_PARTITION_H
+
+#include <sys/types.h>
+
+/* examine and try to publish partitions on a particular device at a particular offset */
+int partition_publish(const char *device, off_t offset);
+
+/* remove any published subdevices on this device */
+int partition_unpublish(const char *device);
+
+#endif
+
diff --git a/include/lib/text.h b/include/lib/text.h
new file mode 100644
index 0000000..ad7b1fd
--- /dev/null
+++ b/include/lib/text.h
@@ -0,0 +1,14 @@
+#ifndef __LIB_TEXT_H
+#define __LIB_TEXT_H
+
+#include <lib/font.h>
+
+/* super cheezy mechanism to stick lines of text up on top of whatever is being drawn */
+/* XXX replace with something more generic later */
+void text_draw(int x, int y, const char *string);
+
+/* super dumb, someone has to call this to refresh everything */
+void text_update(void);
+
+#endif
+
diff --git a/include/lib/tga.h b/include/lib/tga.h
new file mode 100644
index 0000000..62ffb43
--- /dev/null
+++ b/include/lib/tga.h
@@ -0,0 +1,10 @@
+#ifndef __LIB_TGA_H
+#define __LIB_TGA_H
+
+#include <lib/gfx.h>
+#include <sys/types.h>
+
+gfx_surface *tga_decode(const void *ptr, size_t len, gfx_format format);
+
+#endif
+
diff --git a/include/platform/debug.h b/include/platform/debug.h
index 4ab460a..785cd42 100644
--- a/include/platform/debug.h
+++ b/include/platform/debug.h
@@ -32,7 +32,6 @@
#endif
void debug_dump_regs(void);
-uint32_t debug_cycle_count(void);
void debug_dump_memory_bytes(void *mem, int len);
void debug_dump_memory_halfwords(void *mem, int len);
diff --git a/include/pow2.h b/include/pow2.h
new file mode 100644
index 0000000..1ab8ae0
--- /dev/null
+++ b/include/pow2.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __POW2_H
+#define __POW2_H
+
+#include <sys/types.h>
+#include <compiler.h>
+
+/* routines for dealing with power of 2 values for efficiency */
+static inline __ALWAYS_INLINE bool ispow2(uint val)
+{
+ return ((val - 1) & val) == 0;
+}
+
+static inline __ALWAYS_INLINE uint log2(uint val)
+{
+ if (!ispow2(val))
+ return 0; // undefined
+
+ return __builtin_ctz(val);
+}
+
+static inline __ALWAYS_INLINE uint valpow2(uint valp2)
+{
+ return 1 << valp2;
+}
+
+static inline __ALWAYS_INLINE uint divpow2(uint val, uint divp2)
+{
+ return val >> divp2;
+}
+
+static inline __ALWAYS_INLINE uint modpow2(uint val, uint modp2)
+{
+ return val & ((1UL << modp2) - 1);
+}
+
+
+#endif
+
diff --git a/include/sys/types.h b/include/sys/types.h
index 95059fa..9b26eeb 100644
--- a/include/sys/types.h
+++ b/include/sys/types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -62,6 +62,11 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define TIME_GTE(a, b) ((long)((a) - (b)) >= 0)
+#define TIME_LTE(a, b) ((long)((a) - (b)) <= 0)
+#define TIME_GT(a, b) ((long)((a) - (b)) > 0)
+#define TIME_LT(a, b) ((long)((a) - (b)) < 0)
+
enum handler_return {
INT_NO_RESCHEDULE = 0,
INT_RESCHEDULE,
diff --git a/kernel/debug.c b/kernel/debug.c
index c3d7220..ec4b987 100644
--- a/kernel/debug.c
+++ b/kernel/debug.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -21,12 +21,22 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+/**
+ * @defgroup debug Debug
+ * @{
+ */
+
+/**
+ * @file
+ * @brief Debug console functions.
+ */
+
#include <debug.h>
#include <kernel/thread.h>
#include <kernel/timer.h>
#include <platform.h>
-#if defined(WITH_LIB_CONSOLE)
+#if WITH_LIB_CONSOLE
#include <lib/console.h>
static int cmd_threads(int argc, const cmd_args *argv);
@@ -35,11 +45,11 @@
STATIC_COMMAND_START
#if DEBUGLEVEL > 1
- { "threads", "list kernel threads", &cmd_threads },
+STATIC_COMMAND("threads", "list kernel threads", &cmd_threads)
#endif
#if THREAD_STATS
- { "threadstats", "thread level statistics", &cmd_threadstats },
- { "threadload", "toggle thread load display", &cmd_threadload },
+STATIC_COMMAND("threadstats", "thread level statistics", &cmd_threadstats)
+STATIC_COMMAND("threadload", "toggle thread load display", &cmd_threadload)
#endif
STATIC_COMMAND_END(kernel);
@@ -75,8 +85,6 @@
static struct thread_stats old_stats;
static bigtime_t last_idle_time;
- timer_set_oneshot(t, 1000, &threadload, NULL);
-
bigtime_t idle_time = thread_stats.idle_time;
if (current_thread == idle_thread) {
idle_time += current_time_hires() - thread_stats.last_idle_timestamp;
@@ -108,7 +116,7 @@
if (showthreadload == false) {
// start the display
timer_initialize(&tltimer);
- timer_set_oneshot(&tltimer, 1000, &threadload, NULL);
+ timer_set_periodic(&tltimer, 1000, &threadload, NULL);
showthreadload = true;
} else {
timer_cancel(&tltimer);
diff --git a/kernel/event.c b/kernel/event.c
index 09e485a..bdb6ec2 100644
--- a/kernel/event.c
+++ b/kernel/event.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -20,6 +20,26 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+
+/**
+ * @file
+ * @brief Event wait and signal functions for threads.
+ * @defgroup event Events
+ *
+ * An event is a subclass of a wait queue.
+ *
+ * Threads wait for events, with optional timeouts.
+ *
+ * Events are "signaled", releasing waiting threads to continue.
+ * Signals may be one-shot signals (EVENT_FLAG_AUTOUNSIGNAL), in which
+ * case one signal releases only one thread, at which point it is
+ * automatically cleared. Otherwise, signals release all waiting threads
+ * to continue immediately until the signal is manually cleared with
+ * event_unsignal().
+ *
+ * @{
+ */
+
#include <debug.h>
#include <err.h>
#include <kernel/event.h>
@@ -28,6 +48,13 @@
#define EVENT_CHECK 1
#endif
+/**
+ * @brief Initialize an event object
+ *
+ * @param e Event object to initialize
+ * @param initial Initial value for "signaled" state
+ * @param flags 0 or EVENT_FLAG_AUTOUNSIGNAL
+ */
void event_init(event_t *e, bool initial, uint flags)
{
#if EVENT_CHECK
@@ -40,6 +67,15 @@
wait_queue_init(&e->wait);
}
+/**
+ * @brief Destroy an event object.
+ *
+ * Event's resources are freed and it may no longer be
+ * used until event_init() is called again. Any threads
+ * still waiting on the event will be resumed.
+ *
+ * @param e Event object to initialize
+ */
void event_destroy(event_t *e)
{
enter_critical_section();
@@ -56,6 +92,21 @@
exit_critical_section();
}
+/**
+ * @brief Wait for event to be signaled
+ *
+ * If the event has already been signaled, this function
+ * returns immediately. Otherwise, the current thread
+ * goes to sleep until the event object is signaled,
+ * the timeout is reached, or the event object is destroyed
+ * by another thread.
+ *
+ * @param e Event object
+ * @param timeout Timeout value, in ms
+ *
+ * @return 0 on success, ERR_TIMED_OUT on timeout,
+ * other values on other errors.
+ */
status_t event_wait_timeout(event_t *e, time_t timeout)
{
status_t ret = NO_ERROR;
@@ -85,11 +136,31 @@
return ret;
}
+/**
+ * @brief Same as event_wait_timeout(), but without a timeout.
+ */
status_t event_wait(event_t *e)
{
return event_wait_timeout(e, INFINITE_TIME);
}
+/**
+ * @brief Signal an event
+ *
+ * Signals an event. If EVENT_FLAG_AUTOUNSIGNAL is set in the event
+ * object's flags, only one waiting thread is allowed to proceed. Otherwise,
+ * all waiting threads are allowed to proceed until such time as
+ * event_unsignal() is called.
+ *
+ * @param e Event object
+ * @param reschedule If true, waiting thread(s) are executed immediately,
+ * and the current thread resumes only after the
+ * waiting threads have been satisfied. If false,
+ * waiting threads are placed at the end of the run
+ * queue.
+ *
+ * @return Returns NO_ERROR on success.
+ */
status_t event_signal(event_t *e, bool reschedule)
{
enter_critical_section();
@@ -121,6 +192,18 @@
return NO_ERROR;
}
+/**
+ * @brief Clear the "signaled" property of an event
+ *
+ * Used mainly for event objects without the EVENT_FLAG_AUTOUNSIGNAL
+ * flag. Once this function is called, threads that call event_wait()
+ * functions will once again need to wait until the event object
+ * is signaled.
+ *
+ * @param e Event object
+ *
+ * @return Returns NO_ERROR on success.
+ */
status_t event_unsignal(event_t *e)
{
enter_critical_section();
diff --git a/kernel/main.c b/kernel/main.c
index f48ea55..efbb9e9 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -121,6 +121,14 @@
arch_init();
+ // XXX put this somewhere else
+#if WITH_LIB_BIO
+ bio_init();
+#endif
+#if WITH_LIB_FS
+ fs_init();
+#endif
+
// initialize the rest of the platform
dprintf(SPEW, "initializing platform\n");
platform_init();
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 4998b6a..07d2b19 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -20,6 +20,15 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+
+/**
+ * @file
+ * @brief Mutex functions
+ *
+ * @defgroup mutex Mutex
+ * @{
+ */
+
#include <debug.h>
#include <err.h>
#include <kernel/mutex.h>
@@ -29,6 +38,9 @@
#define MUTEX_CHECK 1
#endif
+/**
+ * @brief Initialize a mutex_t
+ */
void mutex_init(mutex_t *m)
{
#if MUTEX_CHECK
@@ -41,6 +53,12 @@
wait_queue_init(&m->wait);
}
+/**
+ * @brief Destroy a mutex_t
+ *
+ * This function frees any resources that were allocated
+ * in mutex_init(). The mutex_t object itself is not freed.
+ */
void mutex_destroy(mutex_t *m)
{
enter_critical_section();
@@ -49,9 +67,9 @@
ASSERT(m->magic == MUTEX_MAGIC);
#endif
- if (m->holder != 0 && current_thread != m->holder)
- panic("mutex_destroy: thread %p (%s) tried to release mutex %p it doesn't own. owned by %p (%s)\n",
- current_thread, current_thread->name, m, m->holder, m->holder ? m->holder->name : "none");
+// if (m->holder != 0 && current_thread != m->holder)
+// panic("mutex_destroy: thread %p (%s) tried to release mutex %p it doesn't own. owned by %p (%s)\n",
+// current_thread, current_thread->name, m, m->holder, m->holder ? m->holder->name : "none");
m->magic = 0;
m->count = 0;
@@ -59,6 +77,14 @@
exit_critical_section();
}
+/**
+ * @brief Acquire a mutex; wait if needed.
+ *
+ * This function waits for a mutex to become available. It
+ * may wait forever if the mutex never becomes free.
+ *
+ * @return NO_ERROR on success, other values on error
+ */
status_t mutex_acquire(mutex_t *m)
{
status_t ret = NO_ERROR;
@@ -94,6 +120,16 @@
return ret;
}
+/**
+ * @brief Mutex wait with timeout
+ *
+ * This function waits up to \a timeout ms for the mutex to become available.
+ * Timeout may be zero, in which case this function returns immediately if
+ * the mutex is not free.
+ *
+ * @return NO_ERROR on success, ERR_TIMED_OUT on timeout,
+ * other values on error
+ */
status_t mutex_acquire_timeout(mutex_t *m, time_t timeout)
{
status_t ret = NO_ERROR;
@@ -140,6 +176,9 @@
return ret;
}
+/**
+ * @brief Release mutex
+ */
status_t mutex_release(mutex_t *m)
{
if (current_thread != m->holder)
diff --git a/kernel/thread.c b/kernel/thread.c
index eeccdd6..58dff8d 100644
--- a/kernel/thread.c
+++ b/kernel/thread.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -20,6 +20,16 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+
+/**
+ * @file
+ * @brief Kernel threading
+ *
+ * This file is the core kernel threading interface.
+ *
+ * @defgroup thread Threads
+ * @{
+ */
#include <debug.h>
#include <list.h>
#include <malloc.h>
@@ -61,6 +71,11 @@
static void thread_resched(void);
static void idle_thread_routine(void) __NO_RETURN;
+#if PLATFORM_HAS_DYNAMIC_TIMER
+/* preemption timer */
+static timer_t preempt_timer;
+#endif
+
/* run queue manipulation */
static void insert_in_run_queue_head(thread_t *t)
{
@@ -95,6 +110,33 @@
strlcpy(t->name, name, sizeof(t->name));
}
+/**
+ * @brief Create a new thread
+ *
+ * This function creates a new thread. The thread is initially suspended, so you
+ * need to call thread_resume() to execute it.
+ *
+ * @param name Name of thread
+ * @param entry Entry point of thread
+ * @param arg Arbitrary argument passed to entry()
+ * @param priority Execution priority for the thread.
+ * @param stack_size Stack size for the thread.
+ *
+ * Thread priority is an integer from 0 (lowest) to 31 (highest). Some standard
+ * prioritys are defined in <kernel/thread.h>:
+ *
+ * HIGHEST_PRIORITY
+ * DPC_PRIORITY
+ * HIGH_PRIORITY
+ * DEFAULT_PRIORITY
+ * LOW_PRIORITY
+ * IDLE_PRIORITY
+ * LOWEST_PRIORITY
+ *
+ * Stack size is typically set to DEFAULT_STACK_SIZE
+ *
+ * @return Pointer to thread object, or NULL on failure.
+ */
thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size)
{
thread_t *t;
@@ -138,6 +180,16 @@
return t;
}
+/**
+ * @brief Make a suspended thread executable.
+ *
+ * This function is typically called to start a thread which has just been
+ * created with thread_create()
+ *
+ * @param t Thread to resume
+ *
+ * @return NO_ERROR on success, ERR_NOT_SUSPENDED if thread was not suspended.
+ */
status_t thread_resume(thread_t *t)
{
#if THREAD_CHECKS
@@ -181,6 +233,13 @@
free(t);
}
+/**
+ * @brief Terminate the current thread
+ *
+ * Current thread exits with the specified return code.
+ *
+ * This function does not return.
+ */
void thread_exit(int retcode)
{
#if THREAD_CHECKS
@@ -211,10 +270,15 @@
arch_idle();
}
-/*
+/**
+ * @brief Cause another thread to be executed.
+ *
* Internal reschedule routine. The current thread needs to already be in whatever
* state and queues it needs to be in. This routine simply picks the next thread and
* switches to it.
+ *
+ * This is probably not the function you're looking for. See
+ * thread_yield() instead.
*/
void thread_resched(void)
{
@@ -294,6 +358,17 @@
ASSERT(newthread->saved_critical_section_count > 0);
#endif
+#if PLATFORM_HAS_DYNAMIC_TIMER
+ /* if we're switching from idle to a real thread, set up a periodic
+ * timer to run our preemption tick.
+ */
+ if (oldthread == idle_thread) {
+ timer_set_periodic(&preempt_timer, 10, (timer_callback)thread_timer_tick, NULL);
+ } else if (newthread == idle_thread) {
+ timer_cancel(&preempt_timer);
+ }
+#endif
+
/* do the switch */
oldthread->saved_critical_section_count = critical_section_count;
current_thread = newthread;
@@ -301,6 +376,15 @@
arch_context_switch(oldthread, newthread);
}
+/**
+ * @brief Yield the cpu to another thread
+ *
+ * This function places the current thread at the end of the run queue
+ * and yields the cpu to another waiting thread (if any.)
+ *
+ * This function will return at some later time. Possibly immediately if
+ * no other threads are waiting to execute.
+ */
void thread_yield(void)
{
#if THREAD_CHECKS
@@ -323,6 +407,21 @@
exit_critical_section();
}
+/**
+ * @brief Briefly yield cpu to another thread
+ *
+ * This function is similar to thread_yield(), except that it will
+ * restart more quickly.
+ *
+ * This function places the current thread at the head of the run
+ * queue and then yields the cpu to another thread.
+ *
+ * Exception: If the time slice for this thread has expired, then
+ * the thread goes to the end of the run queue.
+ *
+ * This function will return at some later time. Possibly immediately if
+ * no other threads are waiting to execute.
+ */
void thread_preempt(void)
{
#if THREAD_CHECKS
@@ -348,6 +447,16 @@
exit_critical_section();
}
+/**
+ * @brief Suspend thread until woken.
+ *
+ * This function schedules another thread to execute. This function does not
+ * return until the thread is made runable again by some other module.
+ *
+ * You probably don't want to call this function directly; it's meant to be called
+ * from other modules, such as mutex, which will presumably set the thread's
+ * state to blocked and add it to some queue or another.
+ */
void thread_block(void)
{
#if THREAD_CHECKS
@@ -391,6 +500,16 @@
return INT_RESCHEDULE;
}
+/**
+ * @brief Put thread to sleep; delay specified in ms
+ *
+ * This function puts the current thread to sleep until the specified
+ * delay in ms has expired.
+ *
+ * Note that this function could sleep for longer than the specified delay if
+ * other threads are running. When the timer expires, this thread will
+ * be placed at the head of the run queue.
+ */
void thread_sleep(time_t delay)
{
timer_t timer;
@@ -409,6 +528,11 @@
exit_critical_section();
}
+/**
+ * @brief Initialize threading system
+ *
+ * This function is called once, from kmain()
+ */
void thread_init_early(void)
{
int i;
@@ -432,15 +556,31 @@
current_thread = t;
}
+/**
+ * @brief Complete thread initialization
+ *
+ * This function is called once at boot time
+ */
void thread_init(void)
{
+#if PLATFORM_HAS_DYNAMIC_TIMER
+ timer_initialize(&preempt_timer);
+#endif
}
+/**
+ * @brief Change name of current thread
+ */
void thread_set_name(const char *name)
{
strlcpy(current_thread->name, name, sizeof(current_thread->name));
}
+/**
+ * @brief Change priority of current thread
+ *
+ * See thread_create() for a discussion of priority values.
+ */
void thread_set_priority(int priority)
{
if (priority < LOWEST_PRIORITY)
@@ -450,6 +590,13 @@
current_thread->priority = priority;
}
+/**
+ * @brief Become an idle thread
+ *
+ * This function marks the current thread as the idle thread -- the one which
+ * executes when there is nothing else to do. This function does not return.
+ * This function is called once at boot time.
+ */
void thread_become_idle(void)
{
thread_set_name("idle");
@@ -458,6 +605,9 @@
idle_thread_routine();
}
+/**
+ * @brief Dump debugging info about the specified thread.
+ */
void dump_thread(thread_t *t)
{
dprintf(INFO, "dump_thread: t %p (%s)\n", t, t->name);
@@ -473,6 +623,9 @@
dprintf(INFO, "\n");
}
+/**
+ * @brief Dump debugging info about all threads
+ */
void dump_all_threads(void)
{
thread_t *t;
@@ -484,7 +637,17 @@
exit_critical_section();
}
-/* wait queue */
+/** @} */
+
+
+/**
+ * @defgroup wait Wait Queue
+ * @{
+ */
+
+/**
+ * @brief Initialize a wait queue
+ */
void wait_queue_init(wait_queue_t *wait)
{
wait->magic = WAIT_QUEUE_MAGIC;
@@ -506,6 +669,24 @@
return INT_NO_RESCHEDULE;
}
+/**
+ * @brief Block until a wait queue is notified.
+ *
+ * This function puts the current thread at the end of a wait
+ * queue and then blocks until some other thread wakes the queue
+ * up again.
+ *
+ * @param wait The wait queue to enter
+ * @param timeout The maximum time, in ms, to wait
+ *
+ * If the timeout is zero, this function returns immediately with
+ * ERR_TIMED_OUT. If the timeout is INFINITE_TIME, this function
+ * waits indefinitely. Otherwise, this function returns with
+ * ERR_TIMED_OUT at the end of the timeout period.
+ *
+ * @return ERR_TIMED_OUT on timeout, else returns the return
+ * value specified when the queue was woken by wait_queue_wake_one().
+ */
status_t wait_queue_block(wait_queue_t *wait, time_t timeout)
{
timer_t timer;
@@ -541,6 +722,20 @@
return current_thread->wait_queue_block_ret;
}
+/**
+ * @brief Wake up one thread sleeping on a wait queue
+ *
+ * This function removes one thread (if any) from the head of the wait queue and
+ * makes it executable. The new thread will be placed at the head of the
+ * run queue.
+ *
+ * @param wait The wait queue to wake
+ * @param reschedule If true, the newly-woken thread will run immediately.
+ * @param wait_queue_error The return value which the new thread will receive
+ * from wait_queue_block().
+ *
+ * @return The number of threads woken (zero or one)
+ */
int wait_queue_wake_one(wait_queue_t *wait, bool reschedule, status_t wait_queue_error)
{
thread_t *t;
@@ -578,6 +773,21 @@
return ret;
}
+
+/**
+ * @brief Wake all threads sleeping on a wait queue
+ *
+ * This function removes all threads (if any) from the wait queue and
+ * makes them executable. The new threads will be placed at the head of the
+ * run queue.
+ *
+ * @param wait The wait queue to wake
+ * @param reschedule If true, the newly-woken threads will run immediately.
+ * @param wait_queue_error The return value which the new thread will receive
+ * from wait_queue_block().
+ *
+ * @return The number of threads woken (zero or one)
+ */
int wait_queue_wake_all(wait_queue_t *wait, bool reschedule, status_t wait_queue_error)
{
thread_t *t;
@@ -621,6 +831,11 @@
return ret;
}
+/**
+ * @brief Free all resources allocated in wait_queue_init()
+ *
+ * If any threads were waiting on this queue, they are all woken.
+ */
void wait_queue_destroy(wait_queue_t *wait, bool reschedule)
{
#if THREAD_CHECKS
@@ -631,6 +846,19 @@
wait->magic = 0;
}
+/**
+ * @brief Wake a specific thread in a wait queue
+ *
+ * This function extracts a specific thread from a wait queue, wakes it, and
+ * puts it at the head of the run queue.
+ *
+ * @param t The thread to wake
+ * @param reschedule If true, the newly-woken threads will run immediately.
+ * @param wait_queue_error The return value which the new thread will receive
+ * from wait_queue_block().
+ *
+ * @return ERR_NOT_BLOCKED if thread was not in any wait queue.
+ */
status_t thread_unblock_from_wait_queue(thread_t *t, bool reschedule, status_t wait_queue_error)
{
enter_critical_section();
diff --git a/kernel/timer.c b/kernel/timer.c
index 71bc4fb..dd5cf9f 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -20,6 +20,20 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+
+/**
+ * @file
+ * @brief Kernel timer subsystem
+ * @defgroup timer Timers
+ *
+ * The timer subsystem allows functions to be scheduled for later
+ * execution. Each timer object is used to cause one function to
+ * be executed at a later time.
+ *
+ * Timer callback functions are called in interrupt context.
+ *
+ * @{
+ */
#include <debug.h>
#include <list.h>
#include <kernel/thread.h>
@@ -29,6 +43,11 @@
static struct list_node timer_queue;
+static enum handler_return timer_tick(void *arg, time_t now);
+
+/**
+ * @brief Initialize a timer object
+ */
void timer_initialize(timer_t *timer)
{
timer->magic = TIMER_MAGIC;
@@ -43,8 +62,10 @@
{
timer_t *entry;
+// TRACEF("timer %p, scheduled %d, periodic %d\n", timer, timer->scheduled_time, timer->periodic_time);
+
list_for_every_entry(&timer_queue, entry, timer_t, node) {
- if (entry->scheduled_time > timer->scheduled_time) {
+ if (TIME_GT(entry->scheduled_time, timer->scheduled_time)) {
list_add_before(&entry->node, &timer->node);
return;
}
@@ -54,11 +75,11 @@
list_add_tail(&timer_queue, &timer->node);
}
-void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, void *arg)
+static void timer_set(timer_t *timer, time_t delay, time_t period, timer_callback callback, void *arg)
{
time_t now;
-// TRACEF("delay %d, callback %p, arg %p\n", delay, callback, arg);
+// TRACEF("timer %p, delay %d, period %d, callback %p, arg %p, now %d\n", timer, delay, period, callback, arg);
DEBUG_ASSERT(timer->magic == TIMER_MAGIC);
@@ -68,7 +89,7 @@
now = current_time();
timer->scheduled_time = now + delay;
- timer->periodic_time = 0;
+ timer->periodic_time = period;
timer->callback = callback;
timer->arg = arg;
@@ -78,18 +99,102 @@
insert_timer_in_queue(timer);
+#if PLATFORM_HAS_DYNAMIC_TIMER
+ if (list_peek_head_type(&timer_queue, timer_t, node) == timer) {
+ /* we just modified the head of the timer queue */
+// TRACEF("setting new timer for %u msecs\n", (uint)delay);
+ platform_set_oneshot_timer(timer_tick, NULL, delay);
+ }
+#endif
+
exit_critical_section();
}
+/**
+ * @brief Set up a timer that executes once
+ *
+ * This function specifies a callback function to be called after a specified
+ * delay. The function will be called one time.
+ *
+ * @param timer The timer to use
+ * @param delay The delay, in ms, before the timer is executed
+ * @param callback The function to call when the timer expires
+ * @param arg The argument to pass to the callback
+ *
+ * The timer function is declared as:
+ * enum handler_return callback(struct timer *, time_t now, void *arg) { ... }
+ */
+void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, void *arg)
+{
+ if (delay == 0)
+ delay = 1;
+ timer_set(timer, delay, 0, callback, arg);
+}
+
+/**
+ * @brief Set up a timer that executes repeatedly
+ *
+ * This function specifies a callback function to be called after a specified
+ * delay. The function will be called repeatedly.
+ *
+ * @param timer The timer to use
+ * @param delay The delay, in ms, before the timer is executed
+ * @param callback The function to call when the timer expires
+ * @param arg The argument to pass to the callback
+ *
+ * The timer function is declared as:
+ * enum handler_return callback(struct timer *, time_t now, void *arg) { ... }
+ */
+void timer_set_periodic(timer_t *timer, time_t period, timer_callback callback, void *arg)
+{
+ if (period == 0)
+ period = 1;
+ timer_set(timer, period, period, callback, arg);
+}
+
+/**
+ * @brief Cancel a pending timer
+ */
void timer_cancel(timer_t *timer)
{
DEBUG_ASSERT(timer->magic == TIMER_MAGIC);
enter_critical_section();
+#if PLATFORM_HAS_DYNAMIC_TIMER
+ timer_t *oldhead = list_peek_head_type(&timer_queue, timer_t, node);
+#endif
+
if (list_in_list(&timer->node))
list_delete(&timer->node);
+ /* to keep it from being reinserted into the queue if called from
+ * periodic timer callback.
+ */
+ timer->periodic_time = 0;
+ timer->callback = NULL;
+ timer->arg = NULL;
+
+#if PLATFORM_HAS_DYNAMIC_TIMER
+ /* see if we've just modified the head of the timer queue */
+ timer_t *newhead = list_peek_head_type(&timer_queue, timer_t, node);
+ if (newhead == NULL) {
+// TRACEF("clearing old hw timer, nothing in the queue\n");
+ platform_stop_timer();
+ } else if (newhead != oldhead) {
+ time_t delay;
+ time_t now = current_time();
+
+ if (TIME_LT(newhead->scheduled_time, now))
+ delay = 0;
+ else
+ delay = newhead->scheduled_time - now;
+
+// TRACEF("setting new timer to %d\n", delay);
+ platform_set_oneshot_timer(timer_tick, NULL, delay);
+ }
+#endif
+
exit_critical_section();
}
@@ -103,10 +208,12 @@
thread_stats.timer_ints++;
#endif
+// TRACEF("now %d\n", now);
+
for (;;) {
/* see if there's an event to process */
timer = list_peek_head_type(&timer_queue, timer_t, node);
- if (likely(!timer || now < timer->scheduled_time))
+ if (likely(!timer || TIME_LT(now, timer->scheduled_time)))
break;
/* process it */
@@ -115,19 +222,48 @@
// timer = list_remove_head_type(&timer_queue, timer_t, node);
// ASSERT(timer);
+// TRACEF("dequeued timer %p, scheduled %d periodic %d\n", timer, timer->scheduled_time, timer->periodic_time);
+
#if THREAD_STATS
thread_stats.timers++;
#endif
-// TRACEF("firing callback %p, arg %p\n", timer->callback, timer->arg);
+ bool periodic = timer->periodic_time > 0;
+
+// TRACEF("timer %p firing callback %p, arg %p\n", timer, timer->callback, timer->arg);
if (timer->callback(timer, now, timer->arg) == INT_RESCHEDULE)
ret = INT_RESCHEDULE;
+
+ /* if it was a periodic timer and it hasn't been requeued
+ * by the callback put it back in the list
+ */
+ if (periodic && !list_in_list(&timer->node) && timer->periodic_time > 0) {
+// TRACEF("periodic timer, period %u\n", (uint)timer->periodic_time);
+ timer->scheduled_time = now + timer->periodic_time;
+ insert_timer_in_queue(timer);
+ }
}
+#if PLATFORM_HAS_DYNAMIC_TIMER
+ /* reset the timer to the next event */
+ timer = list_peek_head_type(&timer_queue, timer_t, node);
+ if (timer) {
+ /* has to be the case or it would have fired already */
+ ASSERT(TIME_GT(timer->scheduled_time, now));
+
+ time_t delay = timer->scheduled_time - now;
+
+// TRACEF("setting new timer for %u msecs for event %p\n", (uint)delay, timer);
+ platform_set_oneshot_timer(timer_tick, NULL, delay);
+ }
+#else
/* let the scheduler have a shot to do quantum expiration, etc */
+ /* in case of dynamic timer, the scheduler will set up a periodic timer */
if (thread_timer_tick() == INT_RESCHEDULE)
ret = INT_RESCHEDULE;
+#endif
+ // XXX fix this, should return ret
return INT_RESCHEDULE;
}
diff --git a/lib/bcache/bcache.c b/lib/bcache/bcache.c
new file mode 100644
index 0000000..8ac5a49
--- /dev/null
+++ b/lib/bcache/bcache.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2007 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <list.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <debug.h>
+#include <lib/bcache.h>
+#include <lib/bio.h>
+
+#define LOCAL_TRACE 0
+
+struct bcache_block {
+ struct list_node node;
+ bnum_t blocknum;
+ int ref_count;
+ bool is_dirty;
+ void *ptr;
+};
+
+struct bcache_stats {
+ uint32_t hits;
+ uint32_t depth;
+ uint32_t misses;
+ uint32_t reads;
+ uint32_t writes;
+};
+
+struct bcache {
+ bdev_t *dev;
+ size_t block_size;
+ int count;
+ struct bcache_stats stats;
+
+ struct list_node free_list;
+ struct list_node lru_list;
+
+ struct bcache_block *blocks;
+};
+
+bcache_t bcache_create(bdev_t *dev, size_t block_size, int block_count)
+{
+ struct bcache *cache;
+
+ cache = malloc(sizeof(struct bcache));
+
+ cache->dev = dev;
+ cache->block_size = block_size;
+ cache->count = block_count;
+ memset(&cache->stats, 0, sizeof(cache->stats));
+
+ list_initialize(&cache->free_list);
+ list_initialize(&cache->lru_list);
+
+ cache->blocks = malloc(sizeof(struct bcache_block) * block_count);
+ int i;
+ for (i=0; i < block_count; i++) {
+ cache->blocks[i].ref_count = 0;
+ cache->blocks[i].is_dirty = false;
+ cache->blocks[i].ptr = malloc(block_size);
+ // add to the free list
+ list_add_head(&cache->free_list, &cache->blocks[i].node);
+ }
+
+ return (bcache_t)cache;
+}
+
+static int flush_block(struct bcache *cache, struct bcache_block *block)
+{
+ int rc;
+
+ rc = bio_write(cache->dev, block->ptr,
+ (off_t)block->blocknum * cache->block_size,
+ cache->block_size);
+ if (rc < 0)
+ goto exit;
+
+ block->is_dirty = false;
+ cache->stats.writes++;
+ rc = 0;
+exit:
+ return (rc);
+}
+
+void bcache_destroy(bcache_t _cache)
+{
+ struct bcache *cache = _cache;
+ int i;
+
+ for (i=0; i < cache->count; i++) {
+ DEBUG_ASSERT(cache->blocks[i].ref_count == 0);
+
+ if (cache->blocks[i].is_dirty)
+ printf("warning: freeing dirty block %u\n",
+ cache->blocks[i].blocknum);
+
+ free(cache->blocks[i].ptr);
+ }
+
+ free(cache);
+}
+
+/* find a block if it's already present */
+static struct bcache_block *find_block(struct bcache *cache, uint blocknum)
+{
+ uint32_t depth = 0;
+ struct bcache_block *block;
+
+ LTRACEF("num %u\n", blocknum);
+
+ block = NULL;
+ list_for_every_entry(&cache->lru_list, block, struct bcache_block, node) {
+ LTRACEF("looking at entry %p, num %u\n", block, block->blocknum);
+ depth++;
+
+ if (block->blocknum == blocknum) {
+ list_delete(&block->node);
+ list_add_tail(&cache->lru_list, &block->node);
+ cache->stats.hits++;
+ cache->stats.depth += depth;
+ return block;
+ }
+ }
+
+ cache->stats.misses++;
+ return NULL;
+}
+
+/* allocate a new block */
+static struct bcache_block *alloc_block(struct bcache *cache)
+{
+ int err;
+ struct bcache_block *block;
+
+ /* pop one off the free list if it's present */
+ block = list_remove_head_type(&cache->free_list, struct bcache_block, node);
+ if (block) {
+ block->ref_count = 0;
+ list_add_tail(&cache->lru_list, &block->node);
+ LTRACEF("found block %p on free list\n", block);
+ return block;
+ }
+
+ /* walk the lru, looking for a free block */
+ list_for_every_entry(&cache->lru_list, block, struct bcache_block, node) {
+ LTRACEF("looking at %p, num %u\n", block, block->blocknum);
+ if (block->ref_count == 0) {
+ if (block->is_dirty) {
+ err = flush_block(cache, block);
+ if (err)
+ return NULL;
+ }
+
+ // add it to the tail of the lru
+ list_delete(&block->node);
+ list_add_tail(&cache->lru_list, &block->node);
+ return block;
+ }
+ }
+
+ return NULL;
+}
+
+static struct bcache_block *find_or_fill_block(struct bcache *cache, uint blocknum)
+{
+ int err;
+
+ LTRACEF("block %u\n", blocknum);
+
+ /* see if it's already in the cache */
+ struct bcache_block *block = find_block(cache, blocknum);
+ if (block == NULL) {
+ LTRACEF("wasn't allocated\n");
+
+ /* allocate a new block and fill it */
+ block = alloc_block(cache);
+ DEBUG_ASSERT(block);
+
+ LTRACEF("wasn't allocated, new block %p\n", block);
+
+ block->blocknum = blocknum;
+ err = bio_read(cache->dev, block->ptr, (off_t)blocknum * cache->block_size, cache->block_size);
+ if (err < 0) {
+ /* free the block, return an error */
+ list_add_tail(&cache->free_list, &block->node);
+ return NULL;
+ }
+
+ cache->stats.reads++;
+ }
+
+ DEBUG_ASSERT(block->blocknum == blocknum);
+
+ return block;
+}
+
+int bcache_read_block(bcache_t _cache, void *buf, uint blocknum)
+{
+ struct bcache *cache = _cache;
+
+ LTRACEF("buf %p, blocknum %u\n", buf, blocknum);
+
+ struct bcache_block *block = find_or_fill_block(cache, blocknum);
+ if (block == NULL) {
+ /* error */
+ return -1;
+ }
+
+ memcpy(buf, block->ptr, cache->block_size);
+ return 0;
+}
+
+int bcache_get_block(bcache_t _cache, void **ptr, uint blocknum)
+{
+ struct bcache *cache = _cache;
+
+ LTRACEF("ptr %p, blocknum %u\n", ptr, blocknum);
+
+ DEBUG_ASSERT(ptr);
+
+ struct bcache_block *block = find_or_fill_block(cache, blocknum);
+ if (block == NULL) {
+ /* error */
+ return -1;
+ }
+
+ /* increment the ref count to keep it from being freed */
+ block->ref_count++;
+ *ptr = block->ptr;
+
+ return 0;
+}
+
+int bcache_put_block(bcache_t _cache, uint blocknum)
+{
+ struct bcache *cache = _cache;
+
+ LTRACEF("blocknum %u\n", blocknum);
+
+ struct bcache_block *block = find_block(cache, blocknum);
+
+ /* be pretty hard on the caller for now */
+ DEBUG_ASSERT(block);
+ DEBUG_ASSERT(block->ref_count > 0);
+
+ block->ref_count--;
+
+ return 0;
+}
+
+int bcache_mark_block_dirty(bcache_t priv, uint blocknum)
+{
+ int err;
+ struct bcache *cache = priv;
+ struct bcache_block *block;
+
+ block = find_block(cache, blocknum);
+ if (!block) {
+ err = -1;
+ goto exit;
+ }
+
+ block->is_dirty = true;
+ err = 0;
+exit:
+ return (err);
+}
+
+int bcache_zero_block(bcache_t priv, uint blocknum)
+{
+ int err;
+ struct bcache *cache = priv;
+ struct bcache_block *block;
+
+ block = find_block(cache, blocknum);
+ if (!block) {
+ block = alloc_block(cache);
+ if (!block) {
+ err = -1;
+ goto exit;
+ }
+
+ block->blocknum = blocknum;
+ }
+
+ memset(block->ptr, 0, cache->block_size);
+ block->is_dirty = true;
+ err = 0;
+exit:
+ return (err);
+}
+
+int bcache_flush(bcache_t priv)
+{
+ int err;
+ struct bcache *cache = priv;
+ struct bcache_block *block;
+
+ list_for_every_entry(&cache->lru_list, block, struct bcache_block, node) {
+ if (block->is_dirty) {
+ err = flush_block(cache, block);
+ if (err)
+ goto exit;
+ }
+ }
+
+ err = 0;
+exit:
+ return (err);
+}
+
+void bcache_dump(bcache_t priv, const char *name)
+{
+ uint32_t finds;
+ struct bcache *cache = priv;
+
+ finds = cache->stats.hits + cache->stats.misses;
+
+ printf("%s: hits=%u(%u%%) depth=%u misses=%u(%u%%) reads=%u writes=%u\n",
+ name,
+ cache->stats.hits,
+ finds ? (cache->stats.hits * 100) / finds : 0,
+ cache->stats.hits ? cache->stats.depth / cache->stats.hits : 0,
+ cache->stats.misses,
+ finds ? (cache->stats.misses * 100) / finds : 0,
+ cache->stats.reads,
+ cache->stats.writes);
+}
diff --git a/lib/bcache/rules.mk b/lib/bcache/rules.mk
new file mode 100644
index 0000000..9927f1b
--- /dev/null
+++ b/lib/bcache/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += lib/bio
+
+OBJS += \
+ $(LOCAL_DIR)/bcache.o
diff --git a/lib/bio/bio.c b/lib/bio/bio.c
new file mode 100644
index 0000000..3c35400
--- /dev/null
+++ b/lib/bio/bio.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include <debug.h>
+#include <err.h>
+#include <string.h>
+#include <list.h>
+#include <lib/bio.h>
+#include <kernel/mutex.h>
+
+#define LOCAL_TRACE 0
+
+struct bdev_struct {
+ struct list_node list;
+ mutex_t lock;
+};
+
+static struct bdev_struct *bdevs;
+
+/* default implementation is to use the read_block hook to 'deblock' the device */
+static ssize_t bio_default_read(struct bdev *dev, void *_buf, off_t offset, size_t len)
+{
+ uint8_t *buf = (uint8_t *)_buf;
+ ssize_t bytes_read = 0;
+ bnum_t block;
+ int err = 0;
+ STACKBUF_DMA_ALIGN(temp, dev->block_size); // temporary buffer for partial block transfers
+
+ /* find the starting block */
+ block = offset / dev->block_size;
+
+ LTRACEF("buf %p, offset %lld, block %u, len %zd\n", buf, offset, block, len);
+ /* handle partial first block */
+ if ((offset % dev->block_size) != 0) {
+ /* read in the block */
+ err = bio_read_block(dev, temp, block, 1);
+ if (err < 0)
+ goto err;
+
+ /* copy what we need */
+ size_t block_offset = offset % dev->block_size;
+ size_t tocopy = MIN(dev->block_size - block_offset, len);
+ memcpy(buf, temp + block_offset, tocopy);
+
+ /* increment our buffers */
+ buf += tocopy;
+ len -= tocopy;
+ bytes_read += tocopy;
+ block++;
+ }
+
+ LTRACEF("buf %p, block %u, len %zd\n", buf, block, len);
+ /* handle middle blocks */
+ if (len >= dev->block_size) {
+ /* do the middle reads */
+ size_t block_count = len / dev->block_size;
+ err = bio_read_block(dev, buf, block, block_count);
+ if (err < 0)
+ goto err;
+
+ /* increment our buffers */
+ size_t bytes = block_count * dev->block_size;
+ DEBUG_ASSERT(bytes <= len);
+
+ buf += bytes;
+ len -= bytes;
+ bytes_read += bytes;
+ block += block_count;
+ }
+
+ LTRACEF("buf %p, block %u, len %zd\n", buf, block, len);
+ /* handle partial last block */
+ if (len > 0) {
+ /* read the block */
+ err = bio_read_block(dev, temp, block, 1);
+ if (err < 0)
+ goto err;
+
+ /* copy the partial block from our temp buffer */
+ memcpy(buf, temp, len);
+
+ bytes_read += len;
+ }
+
+err:
+ /* return error or bytes read */
+ return (err >= 0) ? bytes_read : err;
+}
+
+static ssize_t bio_default_write(struct bdev *dev, const void *_buf, off_t offset, size_t len)
+{
+ const uint8_t *buf = (const uint8_t *)_buf;
+ ssize_t bytes_written = 0;
+ bnum_t block;
+ int err = 0;
+ STACKBUF_DMA_ALIGN(temp, dev->block_size); // temporary buffer for partial block transfers
+
+ /* find the starting block */
+ block = offset / dev->block_size;
+
+ LTRACEF("buf %p, offset %lld, block %u, len %zd\n", buf, offset, block, len);
+ /* handle partial first block */
+ if ((offset % dev->block_size) != 0) {
+ /* read in the block */
+ err = bio_read_block(dev, temp, block, 1);
+ if (err < 0)
+ goto err;
+
+ /* copy what we need */
+ size_t block_offset = offset % dev->block_size;
+ size_t tocopy = MIN(dev->block_size - block_offset, len);
+ memcpy(temp + block_offset, buf, tocopy);
+
+ /* write it back out */
+ err = bio_write_block(dev, temp, block, 1);
+ if (err < 0)
+ goto err;
+
+ /* increment our buffers */
+ buf += tocopy;
+ len -= tocopy;
+ bytes_written += tocopy;
+ block++;
+ }
+
+ LTRACEF("buf %p, block %u, len %zd\n", buf, block, len);
+ /* handle middle blocks */
+ if (len >= dev->block_size) {
+ /* do the middle writes */
+ size_t block_count = len / dev->block_size;
+ err = bio_write_block(dev, buf, block, block_count);
+ if (err < 0)
+ goto err;
+
+ /* increment our buffers */
+ size_t bytes = block_count * dev->block_size;
+ DEBUG_ASSERT(bytes <= len);
+
+ buf += bytes;
+ len -= bytes;
+ bytes_written += bytes;
+ block += block_count;
+ }
+
+ LTRACEF("buf %p, block %u, len %zd\n", buf, block, len);
+ /* handle partial last block */
+ if (len > 0) {
+ /* read the block */
+ err = bio_read_block(dev, temp, block, 1);
+ if (err < 0)
+ goto err;
+
+ /* copy the partial block from our temp buffer */
+ memcpy(temp, buf, len);
+
+ /* write it back out */
+ err = bio_write_block(dev, temp, block, 1);
+ if (err < 0)
+ goto err;
+
+ bytes_written += len;
+ }
+
+err:
+ /* return error or bytes written */
+ return (err >= 0) ? bytes_written : err;
+}
+
+static ssize_t bio_default_erase(struct bdev *dev, off_t offset, size_t len)
+{
+ /* default erase operation is to just write zeros over the device */
+#define ERASE_BUF_SIZE 4096
+ uint8_t *zero_buf;
+
+ zero_buf = calloc(1, ERASE_BUF_SIZE);
+
+ size_t remaining = len;
+ off_t pos = offset;
+ while (remaining > 0) {
+ ssize_t towrite = MIN(remaining, ERASE_BUF_SIZE);
+
+ ssize_t written = bio_write(dev, zero_buf, pos, towrite);
+ if (written < 0)
+ return pos;
+
+ pos += written;
+ remaining -= written;
+
+ if (written < towrite)
+ return pos;
+ }
+
+ return len;
+}
+
+static ssize_t bio_default_read_block(struct bdev *dev, void *buf, bnum_t block, uint count)
+{
+ panic("%s no reasonable default operation\n", __PRETTY_FUNCTION__);
+}
+
+static ssize_t bio_default_write_block(struct bdev *dev, const void *buf, bnum_t block, uint count)
+{
+ panic("%s no reasonable default operation\n", __PRETTY_FUNCTION__);
+}
+
+static void bdev_inc_ref(bdev_t *dev)
+{
+ atomic_add(&dev->ref, 1);
+}
+
+static void bdev_dec_ref(bdev_t *dev)
+{
+ int oldval = atomic_add(&dev->ref, -1);
+ if (oldval == 1) {
+ // last ref, remove it
+ DEBUG_ASSERT(!list_in_list(&dev->node));
+
+ TRACEF("last ref, removing (%s)\n", dev->name);
+
+ // call the close hook if it exists
+ if (dev->close)
+ dev->close(dev);
+
+ free(dev->name);
+ free(dev);
+ }
+}
+
+bdev_t *bio_open(const char *name)
+{
+ bdev_t *bdev = NULL;
+
+ /* see if it's in our list */
+ bdev_t *entry;
+ mutex_acquire(&bdevs->lock);
+ list_for_every_entry(&bdevs->list, entry, bdev_t, node) {
+ DEBUG_ASSERT(entry->ref > 0);
+ if (!strcmp(entry->name, name)) {
+ bdev = entry;
+ bdev_inc_ref(bdev);
+ break;
+ }
+ }
+ mutex_release(&bdevs->lock);
+
+ return bdev;
+}
+
+void bio_close(bdev_t *dev)
+{
+ DEBUG_ASSERT(dev);
+
+ bdev_dec_ref(dev);
+}
+
+ssize_t bio_read(bdev_t *dev, void *buf, off_t offset, size_t len)
+{
+ LTRACEF("dev '%s', buf %p, offset %lld, len %zd\n", dev->name, buf, offset, len);
+
+ DEBUG_ASSERT(dev->ref > 0);
+
+ /* range check */
+ if (offset < 0)
+ return -1;
+ if (offset >= dev->size)
+ return 0;
+ if (len == 0)
+ return 0;
+ if (offset + len > dev->size)
+ len = dev->size - offset;
+
+ return dev->read(dev, buf, offset, len);
+}
+
+ssize_t bio_read_block(bdev_t *dev, void *buf, bnum_t block, uint count)
+{
+ LTRACEF("dev '%s', buf %p, block %d, count %u\n", dev->name, buf, block, count);
+
+ DEBUG_ASSERT(dev->ref > 0);
+
+ /* range check */
+ if (block > dev->block_count)
+ return 0;
+ if (count == 0)
+ return 0;
+ if (block + count > dev->block_count)
+ count = dev->block_count - block;
+
+ return dev->read_block(dev, buf, block, count);
+}
+
+ssize_t bio_write(bdev_t *dev, const void *buf, off_t offset, size_t len)
+{
+ LTRACEF("dev '%s', buf %p, offset %lld, len %zd\n", dev->name, buf, offset, len);
+
+ DEBUG_ASSERT(dev->ref > 0);
+
+ /* range check */
+ if (offset < 0)
+ return -1;
+ if (offset >= dev->size)
+ return 0;
+ if (len == 0)
+ return 0;
+ if (offset + len > dev->size)
+ len = dev->size - offset;
+
+ return dev->write(dev, buf, offset, len);
+}
+
+ssize_t bio_write_block(bdev_t *dev, const void *buf, bnum_t block, uint count)
+{
+ LTRACEF("dev '%s', buf %p, block %d, count %u\n", dev->name, buf, block, count);
+
+ DEBUG_ASSERT(dev->ref > 0);
+
+ /* range check */
+ if (block > dev->block_count)
+ return 0;
+ if (count == 0)
+ return 0;
+ if (block + count > dev->block_count)
+ count = dev->block_count - block;
+
+ return dev->write_block(dev, buf, block, count);
+}
+
+ssize_t bio_erase(bdev_t *dev, off_t offset, size_t len)
+{
+ LTRACEF("dev '%s', offset %lld, len %zd\n", dev->name, offset, len);
+
+ DEBUG_ASSERT(dev->ref > 0);
+
+ /* range check */
+ if (offset < 0)
+ return -1;
+ if (offset >= dev->size)
+ return 0;
+ if (len == 0)
+ return 0;
+ if (offset + len > dev->size)
+ len = dev->size - offset;
+
+ return dev->erase(dev, offset, len);
+}
+
+int bio_ioctl(bdev_t *dev, int request, void *argp)
+{
+ LTRACEF("dev '%s', request %08x, argp %p\n", dev->name, request, argp);
+
+ if (dev->ioctl == NULL) {
+ return ERR_NOT_SUPPORTED;
+ } else {
+ return dev->ioctl(dev, request, argp);
+ }
+}
+
+void bio_initialize_bdev(bdev_t *dev, const char *name, size_t block_size, bnum_t block_count)
+{
+ DEBUG_ASSERT(dev);
+ DEBUG_ASSERT(name);
+ DEBUG_ASSERT(block_size == 512); // XXX can only deal with 512 for now
+
+ list_clear_node(&dev->node);
+ dev->name = strdup(name);
+ dev->block_size = block_size;
+ dev->block_count = block_count;
+ dev->size = (off_t)block_count * block_size;
+ dev->ref = 0;
+
+ /* set up the default hooks, the sub driver should override the block operations at least */
+ dev->read = bio_default_read;
+ dev->read_block = bio_default_read_block;
+ dev->write = bio_default_write;
+ dev->write_block = bio_default_write_block;
+ dev->erase = bio_default_erase;
+ dev->close = NULL;
+}
+
+void bio_register_device(bdev_t *dev)
+{
+ DEBUG_ASSERT(dev);
+
+ LTRACEF(" '%s'\n", dev->name);
+
+ bdev_inc_ref(dev);
+
+ mutex_acquire(&bdevs->lock);
+ list_add_head(&bdevs->list, &dev->node);
+ mutex_release(&bdevs->lock);
+}
+
+void bio_unregister_device(bdev_t *dev)
+{
+ DEBUG_ASSERT(dev);
+
+ LTRACEF(" '%s'\n", dev->name);
+
+ // remove it from the list
+ mutex_acquire(&bdevs->lock);
+ list_delete(&dev->node);
+ mutex_release(&bdevs->lock);
+
+ bdev_dec_ref(dev); // remove the ref the list used to have
+}
+
+void bio_dump_devices(void)
+{
+ printf("block devices:\n");
+ bdev_t *entry;
+ mutex_acquire(&bdevs->lock);
+ list_for_every_entry(&bdevs->list, entry, bdev_t, node) {
+ printf("\t%s, size %lld, bsize %zd, ref %d\n", entry->name, entry->size, entry->block_size, entry->ref);
+ }
+ mutex_release(&bdevs->lock);
+}
+
+void bio_init(void)
+{
+ bdevs = malloc(sizeof(*bdevs));
+
+ list_initialize(&bdevs->list);
+ mutex_init(&bdevs->lock);
+}
+
diff --git a/lib/bio/debug.c b/lib/bio/debug.c
new file mode 100644
index 0000000..90bfc11
--- /dev/null
+++ b/lib/bio/debug.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lib/console.h>
+#include <lib/bio.h>
+#include <lib/partition.h>
+#include <platform.h>
+
+#if defined(WITH_LIB_CONSOLE)
+
+#if DEBUGLEVEL > 0
+static int cmd_bio(int argc, const cmd_args *argv);
+
+STATIC_COMMAND_START
+STATIC_COMMAND("bio", "block io debug commands", &cmd_bio)
+STATIC_COMMAND_END(bio);
+
+static int cmd_bio(int argc, const cmd_args *argv)
+{
+ int rc = 0;
+
+ if (argc < 2) {
+ printf("not enough arguments:\n");
+usage:
+ printf("%s list\n", argv[0].str);
+ printf("%s read <device> <address> <offset> <len>\n", argv[0].str);
+ printf("%s write <device> <address> <offset> <len>\n", argv[0].str);
+ printf("%s erase <device> <offset> <len>\n", argv[0].str);
+ printf("%s ioctl <device> <request> <arg>\n", argv[0].str);
+ printf("%s remove <device>\n", argv[0].str);
+#if WITH_LIB_PARTITION
+ printf("%s partscan <device> [offset]\n", argv[0].str);
+#endif
+ return -1;
+ }
+
+ if (!strcmp(argv[1].str, "list")) {
+ bio_dump_devices();
+ } else if (!strcmp(argv[1].str, "read")) {
+ if (argc < 6) {
+ printf("not enough arguments:\n");
+ goto usage;
+ }
+
+ addr_t address = argv[3].u;
+ off_t offset = argv[4].u; // XXX use long
+ size_t len = argv[5].u;
+
+ bdev_t *dev = bio_open(argv[2].str);
+ if (!dev) {
+ printf("error opening block device\n");
+ return -1;
+ }
+
+ time_t t = current_time();
+ ssize_t err = bio_read(dev, (void *)address, offset, len);
+ t = current_time() - t;
+ dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t));
+
+ bio_close(dev);
+
+ rc = err;
+ } else if (!strcmp(argv[1].str, "write")) {
+ if (argc < 6) {
+ printf("not enough arguments:\n");
+ goto usage;
+ }
+
+ addr_t address = argv[3].u;
+ off_t offset = argv[4].u; // XXX use long
+ size_t len = argv[5].u;
+
+ bdev_t *dev = bio_open(argv[2].str);
+ if (!dev) {
+ printf("error opening block device\n");
+ return -1;
+ }
+
+ time_t t = current_time();
+ ssize_t err = bio_write(dev, (void *)address, offset, len);
+ t = current_time() - t;
+ dprintf(INFO, "bio_write returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t));
+
+ bio_close(dev);
+
+ rc = err;
+ } else if (!strcmp(argv[1].str, "erase")) {
+ if (argc < 5) {
+ printf("not enough arguments:\n");
+ goto usage;
+ }
+
+ off_t offset = argv[3].u; // XXX use long
+ size_t len = argv[4].u;
+
+ bdev_t *dev = bio_open(argv[2].str);
+ if (!dev) {
+ printf("error opening block device\n");
+ return -1;
+ }
+
+ time_t t = current_time();
+ ssize_t err = bio_erase(dev, offset, len);
+ t = current_time() - t;
+ dprintf(INFO, "bio_erase returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t));
+
+ bio_close(dev);
+
+ rc = err;
+ } else if (!strcmp(argv[1].str, "ioctl")) {
+ if (argc < 4) {
+ printf("not enough arguments:\n");
+ goto usage;
+ }
+
+ int request = argv[3].u;
+ int arg = (argc == 5) ? argv[4].u : 0;
+
+ bdev_t *dev = bio_open(argv[2].str);
+ if (!dev) {
+ printf("error opening block device\n");
+ return -1;
+ }
+
+ int err = bio_ioctl(dev, request, (void *)arg);
+ dprintf(INFO, "bio_ioctl returns %d\n", err);
+
+ bio_close(dev);
+
+ rc = err;
+ } else if (!strcmp(argv[1].str, "remove")) {
+ if (argc < 3) {
+ printf("not enough arguments:\n");
+ goto usage;
+ }
+
+ bdev_t *dev = bio_open(argv[2].str);
+ if (!dev) {
+ printf("error opening block device\n");
+ return -1;
+ }
+
+ bio_unregister_device(dev);
+ bio_close(dev);
+#if WITH_LIB_PARTITION
+ } else if (!strcmp(argv[1].str, "partscan")) {
+ if (argc < 3) {
+ printf("not enough arguments:\n");
+ goto usage;
+ }
+
+ off_t offset = 0;
+ if (argc > 3)
+ offset = argv[3].u;
+
+ rc = partition_publish(argv[2].str, offset);
+ dprintf(INFO, "partition_publish returns %d\n", rc);
+#endif
+ } else {
+ printf("unrecognized subcommand\n");
+ goto usage;
+ }
+
+ return rc;
+}
+
+#endif
+
+#endif
+
diff --git a/lib/bio/mem.c b/lib/bio/mem.c
new file mode 100644
index 0000000..9ea2f4d
--- /dev/null
+++ b/lib/bio/mem.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <string.h>
+#include <stdlib.h>
+#include <lib/bio.h>
+
+#define LOCAL_TRACE 0
+
+#define BLOCKSIZE 512
+
+typedef struct mem_bdev {
+ bdev_t dev; // base device
+
+ void *ptr;
+} mem_bdev_t;
+
+static ssize_t mem_bdev_read(bdev_t *bdev, void *buf, off_t offset, size_t len)
+{
+ mem_bdev_t *mem = (mem_bdev_t *)bdev;
+
+ LTRACEF("bdev %s, buf %p, offset %lld, len %zu\n", bdev->name, buf, offset, len);
+
+ memcpy(buf, (uint8_t *)mem->ptr + offset, len);
+
+ return len;
+}
+
+static ssize_t mem_bdev_read_block(struct bdev *bdev, void *buf, bnum_t block, uint count)
+{
+ mem_bdev_t *mem = (mem_bdev_t *)bdev;
+
+ LTRACEF("bdev %s, buf %p, block %u, count %u\n", bdev->name, buf, block, count);
+
+ memcpy(buf, (uint8_t *)mem->ptr + block * BLOCKSIZE, count * BLOCKSIZE);
+
+ return count * BLOCKSIZE;
+}
+
+static ssize_t mem_bdev_write(bdev_t *bdev, const void *buf, off_t offset, size_t len)
+{
+ mem_bdev_t *mem = (mem_bdev_t *)bdev;
+
+ LTRACEF("bdev %s, buf %p, offset %lld, len %zu\n", bdev->name, buf, offset, len);
+
+ memcpy((uint8_t *)mem->ptr + offset, buf, len);
+
+ return len;
+}
+
+static ssize_t mem_bdev_write_block(struct bdev *bdev, const void *buf, bnum_t block, uint count)
+{
+ mem_bdev_t *mem = (mem_bdev_t *)bdev;
+
+ LTRACEF("bdev %s, buf %p, block %u, count %u\n", bdev->name, buf, block, count);
+
+ memcpy((uint8_t *)mem->ptr + block * BLOCKSIZE, buf, count * BLOCKSIZE);
+
+ return count * BLOCKSIZE;
+}
+
+int create_membdev(const char *name, void *ptr, size_t len)
+{
+ mem_bdev_t *mem = malloc(sizeof(mem_bdev_t));
+
+ /* set up the base device */
+ bio_initialize_bdev(&mem->dev, name, BLOCKSIZE, len / BLOCKSIZE);
+
+ /* our bits */
+ mem->ptr = ptr;
+ mem->dev.read = mem_bdev_read;
+ mem->dev.read_block = mem_bdev_read_block;
+ mem->dev.write = mem_bdev_write;
+ mem->dev.write_block = mem_bdev_write_block;
+
+ /* register it */
+ bio_register_device(&mem->dev);
+
+ return 0;
+}
+
diff --git a/lib/bio/rules.mk b/lib/bio/rules.mk
new file mode 100644
index 0000000..aaeb026
--- /dev/null
+++ b/lib/bio/rules.mk
@@ -0,0 +1,9 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES +=
+
+OBJS += \
+ $(LOCAL_DIR)/bio.o \
+ $(LOCAL_DIR)/debug.o \
+ $(LOCAL_DIR)/mem.o \
+ $(LOCAL_DIR)/subdev.o
diff --git a/lib/bio/subdev.c b/lib/bio/subdev.c
new file mode 100644
index 0000000..3512f02
--- /dev/null
+++ b/lib/bio/subdev.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <stdlib.h>
+#include <lib/bio.h>
+
+#define LOCAL_TRACE 0
+
+typedef struct {
+ // inheirit the usual bits
+ bdev_t dev;
+
+ // we're a subdevice of this
+ bdev_t *parent;
+
+ // we're this many blocks into it
+ bnum_t offset;
+} subdev_t;
+
+static ssize_t subdev_read(struct bdev *_dev, void *buf, off_t offset, size_t len)
+{
+ subdev_t *subdev = (subdev_t *)_dev;
+
+ return bio_read(subdev->parent, buf, offset + subdev->offset * subdev->dev.block_size, len);
+}
+
+static ssize_t subdev_read_block(struct bdev *_dev, void *buf, bnum_t block, uint count)
+{
+ subdev_t *subdev = (subdev_t *)_dev;
+
+ return bio_read_block(subdev->parent, buf, block + subdev->offset, count);
+}
+
+static ssize_t subdev_write(struct bdev *_dev, const void *buf, off_t offset, size_t len)
+{
+ subdev_t *subdev = (subdev_t *)_dev;
+
+ return bio_write(subdev->parent, buf, offset + subdev->offset * subdev->dev.block_size, len);
+}
+
+static ssize_t subdev_write_block(struct bdev *_dev, const void *buf, bnum_t block, uint count)
+{
+ subdev_t *subdev = (subdev_t *)_dev;
+
+ return bio_write_block(subdev->parent, buf, block + subdev->offset, count);
+}
+
+static ssize_t subdev_erase(struct bdev *_dev, off_t offset, size_t len)
+{
+ subdev_t *subdev = (subdev_t *)_dev;
+
+ return bio_erase(subdev->parent, offset + subdev->offset * subdev->dev.block_size, len);
+}
+
+static void subdev_close(struct bdev *_dev)
+{
+ subdev_t *subdev = (subdev_t *)_dev;
+
+ bio_close(subdev->parent);
+ subdev->parent = NULL;
+}
+
+status_t bio_publish_subdevice(const char *parent_dev, const char *subdev, bnum_t startblock, size_t len)
+{
+ LTRACEF("parent %s, sub %s, startblock %u, len %zd\n", parent_dev, subdev, startblock, len);
+
+ bdev_t *parent = bio_open(parent_dev);
+ if (!parent)
+ return -1;
+
+ /* make sure we're able to do this */
+ if (startblock + len > parent->block_count)
+ return -1;
+
+ subdev_t *sub = malloc(sizeof(subdev_t));
+ bio_initialize_bdev(&sub->dev, subdev, parent->block_size, len);
+
+ sub->parent = parent;
+ sub->offset = startblock;
+
+ sub->dev.read = &subdev_read;
+ sub->dev.read_block = &subdev_read_block;
+ sub->dev.write = &subdev_write;
+ sub->dev.write_block = &subdev_write_block;
+ sub->dev.erase = &subdev_erase;
+ sub->dev.close = &subdev_close;
+
+ bio_register_device(&sub->dev);
+
+ return 0;
+}
+
diff --git a/lib/cbuf/cbuf.c b/lib/cbuf/cbuf.c
new file mode 100644
index 0000000..4c31295
--- /dev/null
+++ b/lib/cbuf/cbuf.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include <debug.h>
+#include <pow2.h>
+#include <string.h>
+#include <lib/cbuf.h>
+#include <kernel/event.h>
+
+#define LOCAL_TRACE 0
+
+#define INC_POINTER(cbuf, ptr, inc) \
+ modpow2(((ptr) + (inc)), (cbuf)->len_pow2)
+
+void cbuf_initialize(cbuf_t *cbuf, size_t len)
+{
+ DEBUG_ASSERT(cbuf);
+ DEBUG_ASSERT(len > 0);
+ DEBUG_ASSERT(ispow2(len));
+
+ cbuf->head = 0;
+ cbuf->tail = 0;
+ cbuf->len_pow2 = log2(len);
+ cbuf->buf = malloc(len);
+ event_init(&cbuf->event, false, 0);
+
+ LTRACEF("len %zd, len_pow2 %u\n", len, cbuf->len_pow2);
+}
+
+static size_t cbuf_space_avail(cbuf_t *cbuf)
+{
+ return (cbuf->head + valpow2(cbuf->len_pow2) - cbuf->tail - 1);
+}
+
+size_t cbuf_write(cbuf_t *cbuf, const void *_buf, size_t len, bool canreschedule)
+{
+ const char *buf = (const char *)_buf;
+
+ LTRACEF("len %zd\n", len);
+
+ DEBUG_ASSERT(cbuf);
+ DEBUG_ASSERT(_buf);
+ DEBUG_ASSERT(len < valpow2(cbuf->len_pow2));
+
+ enter_critical_section();
+
+ size_t write_len;
+ size_t pos = 0;
+
+ while (pos < len && cbuf_space_avail(cbuf) > 0) {
+ if (cbuf->head >= cbuf->tail) {
+ write_len = MIN(valpow2(cbuf->len_pow2) - cbuf->head, len - pos);
+ } else {
+ write_len = MIN(cbuf->tail - cbuf->head - 1, len - pos);
+ }
+
+ // if it's full, abort and return how much we've written
+ if (write_len == 0) {
+ break;
+ }
+
+ memcpy(cbuf->buf + cbuf->head, buf + pos, write_len);
+
+ cbuf->head = INC_POINTER(cbuf, cbuf->head, write_len);
+ pos += write_len;
+ }
+
+ if (cbuf->head != cbuf->tail)
+ event_signal(&cbuf->event, canreschedule);
+
+ exit_critical_section();
+
+ return pos;
+}
+
+size_t cbuf_read(cbuf_t *cbuf, void *_buf, size_t buflen, bool block)
+{
+ size_t ret;
+ char *buf = (char *)_buf;
+
+ DEBUG_ASSERT(cbuf);
+ DEBUG_ASSERT(_buf);
+
+ enter_critical_section();
+
+ if (block)
+ event_wait(&cbuf->event);
+
+ // see if there's data available
+ if (cbuf->tail != cbuf->head) {
+ size_t pos = 0;
+
+ // loop until we've read everything we need
+ // at most this will make two passes to deal with wraparound
+ while (pos < buflen && cbuf->tail != cbuf->head) {
+ size_t read_len;
+ if (cbuf->head > cbuf->tail) {
+ // simple case where there is no wraparound
+ read_len = MIN(cbuf->head - cbuf->tail, buflen - pos);
+ } else {
+ // read to the end of buffer in this pass
+ read_len = MIN(valpow2(cbuf->len_pow2) - cbuf->tail, buflen - pos);
+ }
+
+ memcpy(buf + pos, cbuf->buf + cbuf->tail, read_len);
+
+ cbuf->tail = INC_POINTER(cbuf, cbuf->tail, read_len);
+ pos += read_len;
+ }
+
+ if (cbuf->tail == cbuf->head) {
+ // we've emptied the buffer, unsignal the event
+ event_unsignal(&cbuf->event);
+ }
+
+ ret = pos;
+ } else {
+ DEBUG_ASSERT(!block);
+ ret = 0;
+ }
+
+ exit_critical_section();
+
+ return ret;
+}
+
diff --git a/lib/cbuf/rules.mk b/lib/cbuf/rules.mk
new file mode 100644
index 0000000..2c57d48
--- /dev/null
+++ b/lib/cbuf/rules.mk
@@ -0,0 +1,4 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+OBJS += \
+ $(LOCAL_DIR)/cbuf.o
diff --git a/lib/font/font.c b/lib/font/font.c
new file mode 100644
index 0000000..2caa8ac
--- /dev/null
+++ b/lib/font/font.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * @brief Font display
+ *
+ * This file contains functions to render fonts onto the graphics drawing
+ * surface.
+ *
+ * @ingroup graphics
+ */
+
+#include <debug.h>
+#include <lib/gfx.h>
+#include <lib/font.h>
+
+#include "font.h"
+
+/**
+ * @brief Draw one character from the built-in font
+ *
+ * @ingroup graphics
+ */
+void font_draw_char(gfx_surface *surface, unsigned char c, int x, int y, uint32_t color)
+{
+ uint i,j;
+ uint line;
+
+ // draw this char into a buffer
+ for (i = 0; i < FONT_Y; i++) {
+ line = FONT[c * FONT_Y + i];
+ for (j = 0; j < FONT_X; j++) {
+ if (line & 0x1)
+ gfx_putpixel(surface, x + j, y + i, color);
+ line = line >> 1;
+ }
+ }
+ gfx_flush_rows(surface, y, y + FONT_Y);
+}
+
+
diff --git a/lib/font/font.h b/lib/font/font.h
new file mode 100644
index 0000000..4a5a15f
--- /dev/null
+++ b/lib/font/font.h
@@ -0,0 +1,136 @@
+#ifndef __FONT_H
+#define __FONT_H
+
+static const unsigned char FONT[] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */
+0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '!' */
+0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '"' */
+0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /* '#' */
+0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /* '$' */
+0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /* '%' */
+0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /* '&' */
+0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ''' */
+0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /* '(' */
+0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /* ')' */
+0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /* '*' */
+0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* '+' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ',' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '-' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* '.' */
+0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /* '/' */
+0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '0' */
+0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* '1' */
+0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* '2' */
+0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '3' */
+0x00, 0x10, 0x18, 0x18, 0x14, 0x14, 0x3e, 0x10, 0x38, 0x00, 0x00, 0x00, /* '4' */
+0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '5' */
+0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '6' */
+0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /* '7' */
+0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* '8' */
+0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /* '9' */
+0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /* ':' */
+0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /* ';' */
+0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /* '<' */
+0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /* '=' */
+0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /* '>' */
+0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /* '?' */
+0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /* '@' */
+0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'A' */
+0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'B' */
+0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'C' */
+0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /* 'D' */
+0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'E' */
+0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'F' */
+0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'G' */
+0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'H' */
+0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /* 'I' */
+0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'J' */
+0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'K' */
+0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'L' */
+0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'M' */
+0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /* 'N' */
+0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'O' */
+0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'P' */
+0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /* 'Q' */
+0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /* 'R' */
+0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'S' */
+0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'T' */
+0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'U' */
+0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'V' */
+0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /* 'W' */
+0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'X' */
+0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'Y' */
+0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /* 'Z' */
+0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /* '[' */
+0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /* '\' */
+0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /* ']' */
+0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '^' */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /* '_' */
+0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '`' */
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'a' */
+0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /* 'b' */
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /* 'c' */
+0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /* 'd' */
+0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /* 'e' */
+0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /* 'f' */
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'g' */
+0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'h' */
+0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'i' */
+0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /* 'j' */
+0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /* 'k' */
+0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /* 'l' */
+0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /* 'm' */
+0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /* 'n' */
+0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /* 'o' */
+0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /* 'p' */
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /* 'q' */
+0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /* 'r' */
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /* 's' */
+0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /* 't' */
+0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /* 'u' */
+0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /* 'v' */
+0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /* 'w' */
+0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /* 'x' */
+0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /* 'y' */
+0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /* 'z' */
+0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /* '{' */
+0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /* '|' */
+0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /* '}' */
+0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* '~' */
+0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /* '' */
+};
+
+#endif
+
diff --git a/lib/font/rules.mk b/lib/font/rules.mk
new file mode 100644
index 0000000..71678d1
--- /dev/null
+++ b/lib/font/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += lib/gfx
+
+OBJS += \
+ $(LOCAL_DIR)/font.o
diff --git a/lib/fs/debug.c b/lib/fs/debug.c
new file mode 100644
index 0000000..6d9b433
--- /dev/null
+++ b/lib/fs/debug.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <string.h>
+#include <lib/console.h>
+#include <lib/fs.h>
+#include <stdlib.h>
+#include <platform.h>
+
+#if defined(WITH_LIB_CONSOLE)
+
+#if DEBUGLEVEL > 1
+static int cmd_fs(int argc, const cmd_args *argv);
+
+STATIC_COMMAND_START
+STATIC_COMMAND("fs", "fs debug commands", &cmd_fs)
+STATIC_COMMAND_END(fs);
+
+extern int fs_mount_type(const char *path, const char *device, const char *name);
+extern int fs_create_file(const char *path, filecookie *fcookie);
+extern int fs_make_dir(const char *path);
+extern int fs_write_file(filecookie fcookie, const void *buf, off_t offset, size_t len);
+
+static int cmd_fs(int argc, const cmd_args *argv)
+{
+ int rc = 0;
+
+ if (argc < 2) {
+notenoughargs:
+ printf("not enough arguments:\n");
+usage:
+ printf("%s mount <path> <device> [<type>]\n", argv[0].str);
+ printf("%s unmount <path>\n", argv[0].str);
+ printf("%s create <path>\n", argv[0].str);
+ printf("%s mkdir <path>\n", argv[0].str);
+ printf("%s read <path> [<offset>] [<len>]\n", argv[0].str);
+ printf("%s write <path> <string> [<offset>]\n", argv[0].str);
+ printf("%s stat <file>\n", argv[0].str);
+ return -1;
+ }
+
+ if (!strcmp(argv[1].str, "mount")) {
+ int err;
+
+ if (argc < 4)
+ goto notenoughargs;
+
+ if (argc < 5)
+ err = fs_mount(argv[2].str, argv[3].str);
+
+ else
+ err = fs_mount_type(argv[2].str, argv[3].str, argv[4].str);
+
+ if (err < 0) {
+ printf("error %d mounting device\n", err);
+ return err;
+ }
+ } else if (!strcmp(argv[1].str, "unmount")) {
+ int err;
+
+ if (argc < 3)
+ goto notenoughargs;
+
+ err = fs_unmount(argv[2].str);
+ if (err < 0) {
+ printf("error %d unmounting device\n", err);
+ return err;
+ }
+ } else if (!strcmp(argv[1].str, "create")) {
+ int err;
+ filecookie cookie;
+
+ if (argc < 3)
+ goto notenoughargs;
+
+ err = fs_create_file(argv[2].str, &cookie);
+ if (err < 0) {
+ printf("error %d creating file\n", err);
+ return err;
+ }
+
+ fs_close_file(cookie);
+ } else if (!strcmp(argv[1].str, "mkdir")) {
+ int err;
+
+ if (argc < 3)
+ goto notenoughargs;
+
+ err = fs_make_dir(argv[2].str);
+ if (err < 0) {
+ printf("error %d making directory\n", err);
+ return err;
+ }
+ } else if (!strcmp(argv[1].str, "read")) {
+ int err;
+ char *buf;
+ off_t off;
+ size_t len;
+ filecookie cookie;
+ struct file_stat stat;
+
+ if (argc < 3)
+ goto notenoughargs;
+
+ err = fs_open_file(argv[2].str, &cookie);
+ if (err < 0) {
+ printf("error %d opening file\n", err);
+ return err;
+ }
+
+ err = fs_stat_file(cookie, &stat);
+ if (err < 0) {
+ printf("error %d stat'ing file\n", err);
+ fs_close_file(cookie);
+ return err;
+ }
+
+ if (argc < 4)
+ off = 0;
+
+ else
+ off = argv[3].u;
+
+ if (argc < 5)
+ len = stat.size - off;
+
+ else
+ len = argv[4].u;
+
+ buf = malloc(len + 1);
+
+ err = fs_read_file(cookie, buf, off, len);
+ if (err < 0) {
+ printf("error %d reading file\n", err);
+ free(buf);
+ fs_close_file(cookie);
+ return err;
+ }
+
+ buf[len] = '\0';
+ printf("%s\n", buf);
+ free(buf);
+ fs_close_file(cookie);
+ } else if (!strcmp(argv[1].str, "write")) {
+ int err;
+ off_t off;
+ filecookie cookie;
+ struct file_stat stat;
+
+ if (argc < 3)
+ goto notenoughargs;
+
+ err = fs_open_file(argv[2].str, &cookie);
+ if (err < 0) {
+ printf("error %d opening file\n", err);
+ return err;
+ }
+
+ err = fs_stat_file(cookie, &stat);
+ if (err < 0) {
+ printf("error %d stat'ing file\n", err);
+ fs_close_file(cookie);
+ return err;
+ }
+
+ if (argc < 5)
+ off = stat.size;
+
+ else
+ off = argv[4].u;
+
+ err = fs_write_file(cookie, argv[3].str, off, strlen(argv[3].str));
+ if (err < 0) {
+ printf("error %d writing file\n", err);
+ fs_close_file(cookie);
+ return err;
+ }
+
+ fs_close_file(cookie);
+ } else if (!strcmp(argv[1].str, "stat")) {
+ int err;
+ struct file_stat stat;
+ filecookie cookie;
+
+ if (argc < 3)
+ goto notenoughargs;
+
+ err = fs_open_file(argv[2].str, &cookie);
+ if (err < 0) {
+ printf("error %d opening file\n", err);
+ return err;
+ }
+
+ err = fs_stat_file(cookie, &stat);
+ if (err < 0) {
+ printf("error %d statting file\n", err);
+ fs_close_file(cookie);
+ return err;
+ }
+
+ printf("stat successful:\n");
+ printf("\tis_dir: %d\n", stat.is_dir ? 1 : 0);
+ printf("\tsize: %lld\n", stat.size);
+
+ fs_close_file(cookie);
+ } else {
+ printf("unrecognized subcommand\n");
+ goto usage;
+ }
+
+ return rc;
+}
+
+#endif
+
+#endif
+
diff --git a/lib/fs/fs.c b/lib/fs/fs.c
new file mode 100644
index 0000000..8389a9d
--- /dev/null
+++ b/lib/fs/fs.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <list.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <lib/fs.h>
+#include <lib/bio.h>
+
+#if WITH_LIB_FS_EXT2
+#include <lib/fs/ext2.h>
+#endif
+#if WITH_LIB_FS_FAT32
+#include <lib/fs/fat32.h>
+#endif
+
+#define LOCAL_TRACE 0
+
+struct fs_type {
+ const char *name;
+ int (*mount)(bdev_t *, fscookie *);
+ int (*unmount)(fscookie);
+ int (*open)(fscookie, const char *, filecookie *);
+ int (*create)(fscookie, const char *, filecookie *);
+ int (*mkdir)(fscookie, const char *);
+ int (*stat)(filecookie, struct file_stat *);
+ int (*read)(filecookie, void *, off_t, size_t);
+ int (*write)(filecookie, const void *, off_t, size_t);
+ int (*close)(filecookie);
+};
+
+struct fs_mount {
+ struct list_node node;
+ char *path;
+ bdev_t *dev;
+ fscookie cookie;
+ int refs;
+ struct fs_type *type;
+};
+
+struct fs_file {
+ filecookie cookie;
+ struct fs_mount *mount;
+};
+
+static struct list_node mounts;
+
+static struct fs_type types[] = {
+#if WITH_LIB_FS_EXT2
+ {
+ .name = "ext2",
+ .mount = ext2_mount,
+ .unmount = ext2_unmount,
+ .open = ext2_open_file,
+ .stat = ext2_stat_file,
+ .read = ext2_read_file,
+ .close = ext2_close_file,
+ },
+#endif
+#if WITH_LIB_FS_FAT32
+ {
+ .name = "fat32",
+ .mount = fat32_mount,
+ .unmount = fat32_unmount,
+ .open = fat32_open_file,
+ .create = fat32_create_file,
+ .mkdir = fat32_make_dir,
+ .stat = fat32_stat_file,
+ .read = fat32_read_file,
+ .write = fat32_write_file,
+ .close = fat32_close_file,
+ },
+#endif
+};
+
+static void test_normalize(const char *in);
+static struct fs_mount *find_mount(const char *path, const char **trimmed_path);
+
+void fs_init(void)
+{
+ list_initialize(&mounts);
+#if 0
+ test_normalize("/");
+ test_normalize("/test");
+ test_normalize("/test/");
+ test_normalize("test/");
+ test_normalize("test");
+ test_normalize("/test//");
+ test_normalize("/test/foo");
+ test_normalize("/test/foo/");
+ test_normalize("/test/foo/bar");
+ test_normalize("/test/foo/bar//");
+ test_normalize("/test//foo/bar//");
+ test_normalize("/test//./foo/bar//");
+ test_normalize("/test//./.foo/bar//");
+ test_normalize("/test//./..foo/bar//");
+ test_normalize("/test//./../foo/bar//");
+ test_normalize("/test/../foo");
+ test_normalize("/test/bar/../foo");
+ test_normalize("../foo");
+ test_normalize("../foo/");
+ test_normalize("/../foo");
+ test_normalize("/../foo/");
+ test_normalize("/../../foo");
+ test_normalize("/bleh/../../foo");
+ test_normalize("/bleh/bar/../../foo");
+ test_normalize("/bleh/bar/../../foo/..");
+ test_normalize("/bleh/bar/../../foo/../meh");
+#endif
+}
+
+static struct fs_mount *find_mount(const char *path, const char **trimmed_path)
+{
+ struct fs_mount *mount;
+ size_t pathlen = strlen(path);
+
+ list_for_every_entry(&mounts, mount, struct fs_mount, node) {
+ size_t mountpathlen = strlen(mount->path);
+ if (pathlen < mountpathlen)
+ continue;
+
+ LTRACEF("comparing %s with %s\n", path, mount->path);
+
+ if (memcmp(path, mount->path, mountpathlen) == 0) {
+ if (trimmed_path)
+ *trimmed_path = &path[mountpathlen];
+
+ return mount;
+ }
+ }
+
+ return NULL;
+}
+
+static int mount(const char *path, const char *device, struct fs_type *type)
+{
+ char temppath[512];
+
+ strlcpy(temppath, path, sizeof(temppath));
+ fs_normalize_path(temppath);
+
+ if(temppath[0] != '/')
+ return ERR_BAD_PATH;
+
+ if (find_mount(temppath, NULL))
+ return ERR_ALREADY_MOUNTED;
+
+ bdev_t *dev = bio_open(device);
+ if (!dev)
+ return ERR_NOT_FOUND;
+
+ fscookie cookie;
+ int err = type->mount(dev, &cookie);
+ if (err < 0) {
+ bio_close(dev);
+ return err;
+ }
+
+ /* create the mount structure and add it to the list */
+ struct fs_mount *mount = malloc(sizeof(struct fs_mount));
+ mount->path = strdup(temppath);
+ mount->dev = dev;
+ mount->cookie = cookie;
+ mount->refs = 1;
+ mount->type = type;
+
+ list_add_head(&mounts, &mount->node);
+
+ return 0;
+}
+
+int fs_mount(const char *path, const char *device)
+{
+ return mount(path, device, &types[0]);
+}
+
+int fs_mount_type(const char *path, const char *device, const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < countof(types); i++) {
+ if (!strcmp(name, types[i].name))
+ return mount(path, device, &types[i]);
+ }
+
+ return ERR_NOT_FOUND;
+}
+
+static void put_mount(struct fs_mount *mount)
+{
+ if (!(--mount->refs)) {
+ list_delete(&mount->node);
+ mount->type->unmount(mount->cookie);
+ free(mount->path);
+ bio_close(mount->dev);
+ free(mount);
+ }
+}
+
+int fs_unmount(const char *path)
+{
+ char temppath[512];
+
+ strlcpy(temppath, path, sizeof(temppath));
+ fs_normalize_path(temppath);
+
+ struct fs_mount *mount = find_mount(temppath, NULL);
+ if (!mount)
+ return ERR_NOT_FOUND;
+
+ put_mount(mount);
+
+ return 0;
+}
+
+
+int fs_open_file(const char *path, filecookie *fcookie)
+{
+ int err;
+ char temppath[512];
+ filecookie cookie;
+
+ strlcpy(temppath, path, sizeof(temppath));
+ fs_normalize_path(temppath);
+
+ LTRACEF("path %s temppath %s\n", path, temppath);
+
+ const char *newpath;
+ struct fs_mount *mount = find_mount(temppath, &newpath);
+ if (!mount)
+ return ERR_NOT_FOUND;
+
+ LTRACEF("path %s temppath %s newpath %s\n", path, temppath, newpath);
+
+ err = mount->type->open(mount->cookie, newpath, &cookie);
+ if (err < 0)
+ return err;
+
+ struct fs_file *f = malloc(sizeof(*f));
+ f->cookie = cookie;
+ f->mount = mount;
+ mount->refs++;
+ *fcookie = f;
+
+ return 0;
+}
+
+int fs_create_file(const char *path, filecookie *fcookie)
+{
+ int err;
+ char temppath[512];
+ filecookie cookie;
+
+ strlcpy(temppath, path, sizeof(temppath));
+ fs_normalize_path(temppath);
+
+ const char *newpath;
+ struct fs_mount *mount = find_mount(temppath, &newpath);
+ if (!mount)
+ return ERR_NOT_FOUND;
+
+ if (!mount->type->create)
+ return ERR_NOT_SUPPORTED;
+
+ err = mount->type->create(mount->cookie, newpath, &cookie);
+ if (err < 0)
+ return err;
+
+ struct fs_file *f = malloc(sizeof(*f));
+ f->cookie = cookie;
+ f->mount = mount;
+ mount->refs++;
+ *fcookie = f;
+
+ return 0;
+}
+
+int fs_make_dir(const char *path)
+{
+ char temppath[512];
+
+ strlcpy(temppath, path, sizeof(temppath));
+ fs_normalize_path(temppath);
+
+ const char *newpath;
+ struct fs_mount *mount = find_mount(temppath, &newpath);
+ if (!mount)
+ return ERR_NOT_FOUND;
+
+ if (!mount->type->mkdir)
+ return ERR_NOT_SUPPORTED;
+
+ return mount->type->mkdir(mount->cookie, newpath);
+}
+
+int fs_read_file(filecookie fcookie, void *buf, off_t offset, size_t len)
+{
+ struct fs_file *f = fcookie;
+
+ return f->mount->type->read(f->cookie, buf, offset, len);
+}
+
+int fs_write_file(filecookie fcookie, const void *buf, off_t offset, size_t len)
+{
+ struct fs_file *f = fcookie;
+
+ if (!f->mount->type->write)
+ return ERR_NOT_SUPPORTED;
+
+ return f->mount->type->write(f->cookie, buf, offset, len);
+}
+
+int fs_close_file(filecookie fcookie)
+{
+ int err;
+ struct fs_file *f = fcookie;
+
+ err = f->mount->type->close(f->cookie);
+ if (err < 0)
+ return err;
+
+ put_mount(f->mount);
+ free(f);
+ return 0;
+}
+
+int fs_stat_file(filecookie fcookie, struct file_stat *stat)
+{
+ struct fs_file *f = fcookie;
+
+ return f->mount->type->stat(f->cookie, stat);
+}
+
+ssize_t fs_load_file(const char *path, void *ptr, size_t maxlen)
+{
+ int err;
+ filecookie cookie;
+
+ /* open the file */
+ err = fs_open_file(path, &cookie);
+ if (err < 0)
+ return err;
+
+ /* stat it for size, see how much we need to read */
+ struct file_stat stat;
+ fs_stat_file(cookie, &stat);
+
+ err = fs_read_file(cookie, ptr, 0, MIN(maxlen, stat.size));
+
+ fs_close_file(cookie);
+
+ return err;
+}
+
+static void test_normalize(const char *in)
+{
+ char path[1024];
+
+ strlcpy(path, in, sizeof(path));
+ fs_normalize_path(path);
+ printf("'%s' -> '%s'\n", in, path);
+}
+
+void fs_normalize_path(char *path)
+{
+ int outpos;
+ int pos;
+ char c;
+ bool done;
+ enum {
+ INITIAL,
+ FIELD_START,
+ IN_FIELD,
+ SEP,
+ SEEN_SEP,
+ DOT,
+ SEEN_DOT,
+ DOTDOT,
+ SEEN_DOTDOT,
+ } state;
+
+ state = INITIAL;
+ pos = 0;
+ outpos = 0;
+ done = false;
+
+ /* remove duplicate path seperators, flatten empty fields (only composed of .), backtrack fields with .., remove trailing slashes */
+ while (!done) {
+ c = path[pos];
+ switch (state) {
+ case INITIAL:
+ if (c == '/') {
+ state = SEP;
+ } else if (c == '.') {
+ state = DOT;
+ } else {
+ state = FIELD_START;
+ }
+ break;
+ case FIELD_START:
+ if (c == '.') {
+ state = DOT;
+ } else if (c == 0) {
+ done = true;
+ } else {
+ state = IN_FIELD;
+ }
+ break;
+ case IN_FIELD:
+ if (c == '/') {
+ state = SEP;
+ } else if (c == 0) {
+ done = true;
+ } else {
+ path[outpos++] = c;
+ pos++;
+ }
+ break;
+ case SEP:
+ pos++;
+ path[outpos++] = '/';
+ state = SEEN_SEP;
+ break;
+ case SEEN_SEP:
+ if (c == '/') {
+ // eat it
+ pos++;
+ } else if (c == 0) {
+ done = true;
+ } else {
+ state = FIELD_START;
+ }
+ break;
+ case DOT:
+ pos++; // consume the dot
+ state = SEEN_DOT;
+ break;
+ case SEEN_DOT:
+ if (c == '.') {
+ // dotdot now
+ state = DOTDOT;
+ } else if (c == '/') {
+ // a field composed entirely of a .
+ // consume the / and move directly to the SEEN_SEP state
+ pos++;
+ state = SEEN_SEP;
+ } else if (c == 0) {
+ done = true;
+ } else {
+ // a field prefixed with a .
+ // emit a . and move directly into the IN_FIELD state
+ path[outpos++] = '.';
+ state = IN_FIELD;
+ }
+ break;
+ case DOTDOT:
+ pos++; // consume the dot
+ state = SEEN_DOTDOT;
+ break;
+ case SEEN_DOTDOT:
+ if (c == '/' || c == 0) {
+ // a field composed entirely of '..'
+ // search back and consume a field we've already emitted
+ if (outpos > 0) {
+ // we have already consumed at least one field
+ outpos--;
+
+ // walk backwards until we find the next field boundary
+ while (outpos > 0) {
+ if (path[outpos - 1] == '/') {
+ break;
+ }
+ outpos--;
+ }
+ }
+ pos++;
+ state = SEEN_SEP;
+ if (c == 0)
+ done = true;
+ } else {
+ // a field prefixed with ..
+ // emit the .. and move directly to the IN_FIELD state
+ path[outpos++] = '.';
+ path[outpos++] = '.';
+ state = IN_FIELD;
+ }
+ break;
+ }
+ }
+
+ /* dont end with trailing slashes */
+ if (outpos > 0 && path[outpos - 1] == '/')
+ outpos--;
+
+ path[outpos++] = 0;
+}
+
diff --git a/lib/fs/rules.mk b/lib/fs/rules.mk
new file mode 100644
index 0000000..c1aa7f4
--- /dev/null
+++ b/lib/fs/rules.mk
@@ -0,0 +1,9 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += \
+
+# lib/fs/ext2
+
+OBJS += \
+ $(LOCAL_DIR)/fs.o \
+ $(LOCAL_DIR)/debug.o
diff --git a/lib/gfx/gfx.c b/lib/gfx/gfx.c
new file mode 100644
index 0000000..9296be4
--- /dev/null
+++ b/lib/gfx/gfx.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @defgroup graphics Graphics
+ *
+ * @{
+ */
+
+/**
+ * @file
+ * @brief Graphics drawing library
+ */
+
+#include <debug.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arch/ops.h>
+#include <sys/types.h>
+#include <lib/gfx.h>
+#include <dev/display.h>
+
+#define LOCAL_TRACE 0
+
+static uint16_t ARGB8888_to_RGB565(uint32_t in)
+{
+ uint16_t out;
+
+ out = (in >> 3) & 0x1f; // b
+ out |= ((in >> 10) & 0x3f) << 5; // g
+ out |= ((in >> 19) & 0x1f) << 11; // r
+
+ return out;
+}
+
+/**
+ * @brief Copy a rectangle of pixels from one part of the display to another.
+ */
+void gfx_copyrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
+{
+ // trim
+ if (x >= surface->width)
+ return;
+ if (x2 >= surface->width)
+ return;
+ if (y >= surface->height)
+ return;
+ if (y2 >= surface->height)
+ return;
+ if (width == 0 || height == 0)
+ return;
+
+ // clip the width to src or dest
+ if (x + width > surface->width)
+ width = surface->width - x;
+ if (x2 + width > surface->width)
+ width = surface->width - x2;
+
+ // clip the height to src or dest
+ if (y + height > surface->height)
+ height = surface->height - y;
+ if (y2 + height > surface->height)
+ height = surface->height - y2;
+
+ surface->copyrect(surface, x, y, width, height, x2, y2);
+}
+
+/**
+ * @brief Fill a rectangle on the screen with a constant color.
+ */
+void gfx_fillrect(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
+{
+ LTRACEF("surface %p, x %u y %u w %u h %u c %u\n", surface, x, y, width, height, color);
+ // trim
+ if (unlikely(x >= surface->width))
+ return;
+ if (y >= surface->height)
+ return;
+ if (width == 0 || height == 0)
+ return;
+
+ // clip the width
+ if (x + width > surface->width)
+ width = surface->width - x;
+
+ // clip the height
+ if (y + height > surface->height)
+ height = surface->height - y;
+
+ surface->fillrect(surface, x, y, width, height, color);
+}
+
+/**
+ * @brief Write a single pixel to the screen.
+ */
+void gfx_putpixel(gfx_surface *surface, uint x, uint y, uint color)
+{
+ if (unlikely(x >= surface->width))
+ return;
+ if (y >= surface->height)
+ return;
+
+ surface->putpixel(surface, x, y, color);
+}
+
+static void putpixel16(gfx_surface *surface, uint x, uint y, uint color)
+{
+ uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
+
+ // colors come in in ARGB 8888 form, flatten them
+ *dest = ARGB8888_to_RGB565(color);
+}
+
+static void putpixel32(gfx_surface *surface, uint x, uint y, uint color)
+{
+ uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
+
+ *dest = color;
+}
+
+static void copyrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
+{
+ // copy
+ const uint16_t *src = &((const uint16_t *)surface->ptr)[x + y * surface->stride];
+ uint16_t *dest = &((uint16_t *)surface->ptr)[x2 + y2 * surface->stride];
+ uint stride_diff = surface->stride - width;
+
+ if (dest < src) {
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = *src;
+ dest++;
+ src++;
+ }
+ dest += stride_diff;
+ src += stride_diff;
+ }
+ } else {
+ // copy backwards
+ src += height * surface->stride + width;
+ dest += height * surface->stride + width;
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = *src;
+ dest--;
+ src--;
+ }
+ dest -= stride_diff;
+ src -= stride_diff;
+ }
+ }
+}
+
+static void fillrect16(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
+{
+ uint16_t *dest = &((uint16_t *)surface->ptr)[x + y * surface->stride];
+ uint stride_diff = surface->stride - width;
+
+ uint16_t color16 = ARGB8888_to_RGB565(color);
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = color16;
+ dest++;
+ }
+ dest += stride_diff;
+ }
+}
+
+static void copyrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint x2, uint y2)
+{
+ // copy
+ const uint32_t *src = &((const uint32_t *)surface->ptr)[x + y * surface->stride];
+ uint32_t *dest = &((uint32_t *)surface->ptr)[x2 + y2 * surface->stride];
+ uint stride_diff = surface->stride - width;
+
+ if (dest < src) {
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = *src;
+ dest++;
+ src++;
+ }
+ dest += stride_diff;
+ src += stride_diff;
+ }
+ } else {
+ // copy backwards
+ src += height * surface->stride + width;
+ dest += height * surface->stride + width;
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = *src;
+ dest--;
+ src--;
+ }
+ dest -= stride_diff;
+ src -= stride_diff;
+ }
+ }
+}
+
+static void fillrect32(gfx_surface *surface, uint x, uint y, uint width, uint height, uint color)
+{
+ uint32_t *dest = &((uint32_t *)surface->ptr)[x + y * surface->stride];
+ uint stride_diff = surface->stride - width;
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = color;
+ dest++;
+ }
+ dest += stride_diff;
+ }
+}
+
+uint32_t alpha32_add_ignore_destalpha(uint32_t dest, uint32_t src)
+{
+ uint32_t cdest[3];
+ uint32_t csrc[3];
+
+ uint32_t srca;
+ uint32_t srcainv;
+
+ srca = (src >> 24) & 0xff;
+ if (srca == 0) {
+ return dest;
+ } else if (srca == 255) {
+ return src;
+ }
+ srca++;
+ srcainv = (255 - srca);
+
+ cdest[0] = (dest >> 16) & 0xff;
+ cdest[1] = (dest >> 8) & 0xff;
+ cdest[2] = (dest >> 0) & 0xff;
+
+ csrc[0] = (src >> 16) & 0xff;
+ csrc[1] = (src >> 8) & 0xff;
+ csrc[2] = (src >> 0) & 0xff;
+
+// if (srca > 0)
+// printf("s %d %d %d d %d %d %d a %d ai %d\n", csrc[0], csrc[1], csrc[2], cdest[0], cdest[1], cdest[2], srca, srcainv);
+
+ uint32_t cres[3];
+
+ cres[0] = ((csrc[0] * srca) / 256) + ((cdest[0] * srcainv) / 256);
+ cres[1] = ((csrc[1] * srca) / 256) + ((cdest[1] * srcainv) / 256);
+ cres[2] = ((csrc[2] * srca) / 256) + ((cdest[2] * srcainv) / 256);
+
+ return (srca << 24) | (cres[0] << 16) | (cres[1] << 8) | (cres[2]);
+}
+
+/**
+ * @brief Copy pixels from source to dest.
+ *
+ * Currently does not support alpha channel.
+ */
+void gfx_surface_blend(struct gfx_surface *target, struct gfx_surface *source, uint destx, uint desty)
+{
+ DEBUG_ASSERT(target->format == source->format);
+
+ LTRACEF("target %p, source %p, destx %u, desty %u\n", target, source, destx, desty);
+
+ if (destx >= target->width)
+ return;
+ if (desty >= target->height)
+ return;
+
+ uint width = source->width;
+ if (destx + width > target->width)
+ width = target->width - destx;
+
+ uint height = source->height;
+ if (desty + height > target->height)
+ height = target->height - desty;
+
+ // XXX total hack to deal with various blends
+ if (source->format == GFX_FORMAT_RGB_565 && target->format == GFX_FORMAT_RGB_565) {
+ // 16 bit to 16 bit
+ const uint16_t *src = (const uint16_t *)source->ptr;
+ uint16_t *dest = &((uint16_t *)target->ptr)[destx + desty * target->stride];
+ uint dest_stride_diff = target->stride - width;
+ uint source_stride_diff = source->stride - width;
+
+ LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = *src;
+ dest++;
+ src++;
+ }
+ dest += dest_stride_diff;
+ src += source_stride_diff;
+ }
+ } else if (source->format == GFX_FORMAT_ARGB_8888 && target->format == GFX_FORMAT_ARGB_8888) {
+ // both are 32 bit modes, both alpha
+ const uint32_t *src = (const uint32_t *)source->ptr;
+ uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
+ uint dest_stride_diff = target->stride - width;
+ uint source_stride_diff = source->stride - width;
+
+ LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ // XXX ignores destination alpha
+ *dest = alpha32_add_ignore_destalpha(*dest, *src);
+ dest++;
+ src++;
+ }
+ dest += dest_stride_diff;
+ src += source_stride_diff;
+ }
+ } else if (source->format == GFX_FORMAT_RGB_x888 && target->format == GFX_FORMAT_RGB_x888) {
+ // both are 32 bit modes, no alpha
+ const uint32_t *src = (const uint32_t *)source->ptr;
+ uint32_t *dest = &((uint32_t *)target->ptr)[destx + desty * target->stride];
+ uint dest_stride_diff = target->stride - width;
+ uint source_stride_diff = source->stride - width;
+
+ LTRACEF("w %u h %u dstride %u sstride %u\n", width, height, dest_stride_diff, source_stride_diff);
+
+ uint i, j;
+ for (i=0; i < height; i++) {
+ for (j=0; j < width; j++) {
+ *dest = *src;
+ dest++;
+ src++;
+ }
+ dest += dest_stride_diff;
+ src += source_stride_diff;
+ }
+ } else {
+ panic("gfx_surface_blend: unimplemented colorspace combination (source %d target %d)\n", source->format, target->format);
+ }
+}
+
+/**
+ * @brief Ensure all graphics rendering is sent to display
+ */
+void gfx_flush(gfx_surface *surface)
+{
+ arch_clean_cache_range((addr_t)surface->ptr, surface->len);
+
+ if (surface->flush)
+ surface->flush(0, surface->height-1);
+}
+
+/**
+ * @brief Ensure that a sub-region of the display is up to date.
+ */
+void gfx_flush_rows(struct gfx_surface *surface, uint start, uint end)
+{
+ if (start > end) {
+ uint temp = start;
+ start = end;
+ end = temp;
+ }
+
+ if (start >= surface->height)
+ return;
+ if (end >= surface->height)
+ end = surface->height - 1;
+
+ arch_clean_cache_range((addr_t)surface->ptr + start * surface->stride * surface->pixelsize, (end - start + 1) * surface->stride * surface->pixelsize);
+
+ if (surface->flush)
+ surface->flush(start, end);
+
+}
+
+
+/**
+ * @brief Create a new graphics surface object
+ */
+gfx_surface *gfx_create_surface(void *ptr, uint width, uint height, uint stride, gfx_format format)
+{
+ DEBUG_ASSERT(width > 0);
+ DEBUG_ASSERT(height > 0);
+ DEBUG_ASSERT(stride >= width);
+ DEBUG_ASSERT(format < GFX_FORMAT_MAX);
+
+ gfx_surface *surface = malloc(sizeof(gfx_surface));
+
+ surface->free_on_destroy = false;
+ surface->format = format;
+ surface->width = width;
+ surface->height = height;
+ surface->stride = stride;
+ surface->alpha = MAX_ALPHA;
+
+ // set up some function pointers
+ switch (format) {
+ case GFX_FORMAT_RGB_565:
+ surface->copyrect = ©rect16;
+ surface->fillrect = &fillrect16;
+ surface->putpixel = &putpixel16;
+ surface->pixelsize = 2;
+ surface->len = surface->height * surface->stride * surface->pixelsize;
+ break;
+ case GFX_FORMAT_RGB_x888:
+ case GFX_FORMAT_ARGB_8888:
+ surface->copyrect = ©rect32;
+ surface->fillrect = &fillrect32;
+ surface->putpixel = &putpixel32;
+ surface->pixelsize = 4;
+ surface->len = surface->height * surface->stride * surface->pixelsize;
+ break;
+ default:
+ dprintf(INFO, "invalid graphics format\n");
+ DEBUG_ASSERT(0);
+ free(surface);
+ return NULL;
+ }
+
+ if (ptr == NULL) {
+ // allocate a buffer
+ ptr = malloc(surface->len);
+ DEBUG_ASSERT(ptr);
+ surface->free_on_destroy = true;
+ }
+ surface->ptr = ptr;
+
+ return surface;
+}
+
+/**
+ * @brief Create a new graphics surface object from a display
+ */
+gfx_surface *gfx_create_surface_from_display(struct display_info *info)
+{
+ gfx_surface* surface;
+ surface = gfx_create_surface(info->framebuffer, info->width, info->height, info->stride, info->format);
+
+ surface->flush = info->flush;
+
+ return surface;
+}
+
+/**
+ * @brief Destroy a graphics surface and free all resources allocated to it.
+ *
+ * @param surface Surface to destroy. This pointer is no longer valid after
+ * this call.
+ */
+void gfx_surface_destroy(struct gfx_surface *surface)
+{
+ if (surface->free_on_destroy)
+ free(surface->ptr);
+ free(surface);
+}
+
+/**
+ * @brief Write a test pattern to the default display.
+ */
+void gfx_draw_pattern(void)
+{
+ struct display_info info;
+ display_get_info(&info);
+
+ gfx_surface *surface = gfx_create_surface_from_display(&info);
+
+ uint x, y;
+ for (y = 0; y < surface->height; y++) {
+ for (x = 0; x < surface->width; x++) {
+ uint scaledx;
+ uint scaledy;
+
+ scaledx = x * 256 / surface->width;
+ scaledy = y * 256 / surface->height;
+
+ gfx_putpixel(surface, x, y, (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1);
+ }
+ }
+
+ if (surface->flush)
+ surface->flush(0, surface->height-1);
+
+ gfx_surface_destroy(surface);
+}
+
+/**
+ * @brief Fill default display with white
+ */
+void gfx_draw_pattern_white(void)
+{
+ struct display_info info;
+ display_get_info(&info);
+
+ gfx_surface *surface = gfx_create_surface_from_display(&info);
+
+ uint x, y;
+ for (y = 0; y < surface->height; y++) {
+ for (x = 0; x < surface->width; x++) {
+ gfx_putpixel(surface, x, y, 0xFFFFFF);
+ }
+ }
+
+ if (surface->flush)
+ surface->flush(0, surface->height-1);
+
+ gfx_surface_destroy(surface);
+}
+
+#if defined(WITH_LIB_CONSOLE)
+
+#if DEBUGLEVEL > 1
+#include <lib/console.h>
+
+static int cmd_gfx(int argc, const cmd_args *argv);
+
+STATIC_COMMAND_START
+STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx)
+STATIC_COMMAND_END(gfx);
+
+static int gfx_draw_rgb_bars(gfx_surface *surface)
+{
+ uint x, y;
+
+ int step32 = surface->height*100 / 32;
+ int step64 = surface->height*100 / 64;
+ int color;
+
+ for (y = 0; y < surface->height; y++) {
+ //R
+ for (x = 0; x < surface->width/3; x++) {
+ color = y*100 / step32;
+ gfx_putpixel(surface, x, y, color << 16);
+ }
+ //G
+ for (;x < 2*(surface->width/3); x++) {
+ color = y*100 / step64;
+ gfx_putpixel(surface, x, y, color << 8);
+ }
+ //B
+ for (;x < surface->width; x++) {
+ color = y*100 / step32;
+ gfx_putpixel(surface, x, y, color);
+ }
+ }
+
+ return 0;
+}
+
+
+static int cmd_gfx(int argc, const cmd_args *argv)
+{
+ if (argc < 2) {
+ printf("not enough arguments:\n");
+usage:
+ printf("%s rgb_bars : Fill frame buffer with rgb bars\n", argv[0].str);
+ printf("%s fill r g b : Fill frame buffer with RGB565 value and force update\n", argv[0].str);
+
+ return -1;
+ }
+
+ struct display_info info;
+ display_get_info(&info);
+
+ gfx_surface *surface = gfx_create_surface_from_display(&info);
+
+ if (!strcmp(argv[1].str, "rgb_bars"))
+ {
+ gfx_draw_rgb_bars(surface);
+ }
+ else if (!strcmp(argv[1].str, "fill"))
+ {
+ uint x, y;
+
+ for (y = 0; y < surface->height; y++)
+ {
+ for (x = 0; x < surface->width; x++)
+ {
+ /* write pixel to frame buffer */
+ gfx_putpixel(surface, x, y, (argv[2].i << 16) | (argv[3].i << 8) | argv[4].i);
+ }
+ }
+ }
+
+ if (surface->flush)
+ surface->flush(0, surface->height-1);
+
+ gfx_surface_destroy(surface);
+
+ return 0;
+}
+
+#endif
+#endif
diff --git a/lib/gfx/rules.mk b/lib/gfx/rules.mk
new file mode 100644
index 0000000..9527360
--- /dev/null
+++ b/lib/gfx/rules.mk
@@ -0,0 +1,4 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+OBJS += \
+ $(LOCAL_DIR)/gfx.o
diff --git a/lib/gfxconsole/gfxconsole.c b/lib/gfxconsole/gfxconsole.c
new file mode 100644
index 0000000..8f1fb13
--- /dev/null
+++ b/lib/gfxconsole/gfxconsole.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * @brief Manage graphics console
+ *
+ * This file contains functions to provide stdout to the graphics console.
+ *
+ * @ingroup graphics
+ */
+
+#include <debug.h>
+#include <lib/gfx.h>
+#include <lib/gfxconsole.h>
+#include <lib/font.h>
+#include <dev/display.h>
+
+/** @addtogroup graphics
+ * @{
+ */
+
+/**
+ * @brief Represent state of graphics console
+ */
+static struct {
+ gfx_surface *surface;
+ uint rows, columns;
+ uint extray; // extra pixels left over if the rows doesn't fit precisely
+
+ uint x, y;
+
+ uint32_t front_color;
+ uint32_t back_color;
+} gfxconsole;
+
+static void gfxconsole_putc(char c)
+{
+ static enum { NORMAL, ESCAPE } state = NORMAL;
+ static uint32_t p_num = 0;
+
+ switch (state) {
+ case NORMAL:
+ {
+ if(c == '\n' || c == '\r') {
+ gfxconsole.x = 0;
+ gfxconsole.y++;
+ } else if (c == 0x1b) {
+ p_num = 0;
+ state = ESCAPE;
+ } else {
+ font_draw_char(gfxconsole.surface, c, gfxconsole.x * FONT_X, gfxconsole.y * FONT_Y, gfxconsole.front_color);
+ gfxconsole.x++;
+ }
+ break;
+ }
+
+ case ESCAPE:
+ {
+ if (c >= '0' && c <= '9') {
+ p_num = (p_num * 10) + (c - '0');
+ } else if (c == 'D') {
+ if (p_num <= gfxconsole.x)
+ gfxconsole.x -= p_num;
+ state = NORMAL;
+ } else if (c == '[') {
+ // eat this character
+ } else {
+ font_draw_char(gfxconsole.surface, c, gfxconsole.x * FONT_X, gfxconsole.y * FONT_Y, gfxconsole.front_color);
+ gfxconsole.x++;
+ state = NORMAL;
+ }
+ break;
+ }
+ }
+
+ if(gfxconsole.x >= gfxconsole.columns) {
+ gfxconsole.x = 0;
+ gfxconsole.y++;
+ }
+ if(gfxconsole.y >= gfxconsole.rows) {
+ // scroll up
+ gfx_copyrect(gfxconsole.surface, 0, FONT_Y, gfxconsole.surface->width, gfxconsole.surface->height - FONT_Y - gfxconsole.extray, 0, 0);
+ gfxconsole.y--;
+ gfx_fillrect(gfxconsole.surface, 0, gfxconsole.surface->height - FONT_Y - gfxconsole.extray, gfxconsole.surface->width, FONT_Y, gfxconsole.back_color);
+ gfx_flush(gfxconsole.surface);
+ }
+}
+
+/**
+ * @brief Initialize graphics console on given drawing surface.
+ *
+ * The graphics console subsystem is initialized, and registered as
+ * an output device for debug output.
+ */
+void gfxconsole_start(gfx_surface *surface)
+{
+ DEBUG_ASSERT(gfxconsole.surface == NULL);
+
+ // set up the surface
+ gfxconsole.surface = surface;
+
+ // calculate how many rows/columns we have
+ gfxconsole.rows = surface->height / FONT_Y;
+ gfxconsole.columns = surface->width / FONT_X;
+ gfxconsole.extray = surface->height - (gfxconsole.rows * FONT_Y);
+
+ dprintf(SPEW, "gfxconsole: rows %d, columns %d, extray %d\n", gfxconsole.rows, gfxconsole.columns, gfxconsole.extray);
+
+ // start in the upper left
+ gfxconsole.x = 0;
+ gfxconsole.y = 0;
+
+ // colors are white and black for now
+ gfxconsole.front_color = 0xffffffff;
+ gfxconsole.back_color = 0;
+
+ // register for debug callbacks
+ register_debug_output(&gfxconsole_putc);
+}
+
+/**
+ * @brief Initialize graphics console on default display
+ */
+void gfxconsole_start_on_display(void)
+{
+ static bool started = false;
+
+ if (started)
+ return;
+
+ /* pop up the console */
+ struct display_info info;
+ display_get_info(&info);
+ gfx_surface *s = gfx_create_surface_from_display(&info);
+ gfxconsole_start(s);
+ started = true;
+}
+
diff --git a/lib/gfxconsole/rules.mk b/lib/gfxconsole/rules.mk
new file mode 100644
index 0000000..a61382b
--- /dev/null
+++ b/lib/gfxconsole/rules.mk
@@ -0,0 +1,7 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += lib/gfx \
+ lib/font
+
+OBJS += \
+ $(LOCAL_DIR)/gfxconsole.o
diff --git a/lib/heap/heap.c b/lib/heap/heap.c
index c67bc25..385d13a 100644
--- a/lib/heap/heap.c
+++ b/lib/heap/heap.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
+ * Copyright (c) 2009 Corey Tabaka
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -30,6 +31,12 @@
#define LOCAL_TRACE 0
+#define DEBUG_HEAP 0
+#define ALLOC_FILL 0x99
+#define FREE_FILL 0x77
+#define PADDING_FILL 0x55
+#define PADDING_SIZE 64
+
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
#define HEAP_MAGIC 'HEAP'
@@ -45,10 +52,10 @@
extern int _end;
// end of memory
-extern int _end_of_ram;
+extern int _heap_end;
#define HEAP_START ((unsigned long)&_end)
-#define HEAP_LEN ((size_t)&_end_of_ram - (size_t)&_end)
+#define HEAP_LEN ((size_t)_heap_end - (size_t)&_end)
#endif
struct free_heap_chunk {
@@ -70,6 +77,10 @@
unsigned int magic;
void *ptr;
size_t size;
+#if DEBUG_HEAP
+ void *padding_start;
+ size_t padding_size;
+#endif
};
static void dump_free_chunk(struct free_heap_chunk *chunk)
@@ -203,6 +214,10 @@
{
DEBUG_ASSERT((len % sizeof(void *)) == 0); // size must be aligned on pointer boundary
+#if DEBUG_HEAP
+ memset(ptr, FREE_FILL, len);
+#endif
+
struct free_heap_chunk *chunk = (struct free_heap_chunk *)ptr;
chunk->len = len;
@@ -212,6 +227,9 @@
void *heap_alloc(size_t size, unsigned int alignment)
{
void *ptr;
+#if DEBUG_HEAP
+ size_t original_size = size;
+#endif
LTRACEF("size %zd, align %d\n", size, alignment);
@@ -221,7 +239,10 @@
// we always put a size field + base pointer + magic in front of the allocation
size += sizeof(struct alloc_struct_begin);
-
+#if DEBUG_HEAP
+ size += PADDING_SIZE;
+#endif
+
// make sure we allocate at least the size of a struct free_heap_chunk so that
// when we free it, we can create a struct free_heap_chunk struct and stick it
// in the spot
@@ -275,6 +296,10 @@
DEBUG_ASSERT(chunk->len >= size);
size = chunk->len;
+#if DEBUG_HEAP
+ memset(ptr, ALLOC_FILL, size);
+#endif
+
ptr = (void *)((addr_t)ptr + sizeof(struct alloc_struct_begin));
// align the output if requested
@@ -287,6 +312,13 @@
as->magic = HEAP_MAGIC;
as->ptr = (void *)chunk;
as->size = size;
+#if DEBUG_HEAP
+ as->padding_start = ((uint8_t *)ptr + original_size);
+ as->padding_size = (((addr_t)chunk + size) - ((addr_t)ptr + original_size));
+// printf("padding start %p, size %u, chunk %p, size %u\n", as->padding_start, as->padding_size, chunk, size);
+
+ memset(as->padding_start, PADDING_FILL, as->padding_size);
+#endif
break;
}
@@ -314,6 +346,21 @@
DEBUG_ASSERT(as->magic == HEAP_MAGIC);
+#if DEBUG_HEAP
+ {
+ uint i;
+ uint8_t *pad = (uint8_t *)as->padding_start;
+
+ for (i = 0; i < as->padding_size; i++) {
+ if (pad[i] != PADDING_FILL) {
+ printf("free at %p scribbled outside the lines:\n", ptr);
+ hexdump(pad, as->padding_size);
+ panic("die\n");
+ }
+ }
+ }
+#endif
+
LTRACEF("allocation was %zd bytes long at ptr %p\n", as->size, as->ptr);
// looks good, create a free chunk and add it to the pool
@@ -355,7 +402,7 @@
static int cmd_heap(int argc, const cmd_args *argv);
STATIC_COMMAND_START
- { "heap", "heap debug commands", &cmd_heap },
+STATIC_COMMAND("heap", "heap debug commands", &cmd_heap)
STATIC_COMMAND_END(heap);
static int cmd_heap(int argc, const cmd_args *argv)
diff --git a/lib/libc/printf.c b/lib/libc/printf.c
index b7bf2bb..8a3aeb6 100644
--- a/lib/libc/printf.c
+++ b/lib/libc/printf.c
@@ -39,7 +39,7 @@
int getc(char *c)
{
- return dgetc(c);
+ return dgetc(c, true);
}
int printf(const char *fmt, ...)
diff --git a/lib/libc/string/arch/x86/memcpy.S b/lib/libc/string/arch/x86/memcpy.S
new file mode 100644
index 0000000..a2a2a44
--- /dev/null
+++ b/lib/libc/string/arch/x86/memcpy.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+
+/* TODO: */
+
+.text
+.align 2
+
+/* void bcopy(const void *src, void *dest, size_t n); */
+FUNCTION(bcopy)
+ ret
+
+/* void *memcpy(void *dest, const void *src, size_t n); */
+FUNCTION(memmove)
+FUNCTION(memcpy)
+ ret
+
diff --git a/lib/libc/string/arch/x86/memset.S b/lib/libc/string/arch/x86/memset.S
new file mode 100644
index 0000000..b4bccc9
--- /dev/null
+++ b/lib/libc/string/arch/x86/memset.S
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+
+/* TODO: */
+
+.text
+.align 2
+
+/* void bzero(void *s, size_t n); */
+FUNCTION(bzero)
+ ret
+
+/* void *memset(void *s, int c, size_t n); */
+FUNCTION(memset)
+ ret
+
diff --git a/lib/libc/string/arch/x86/rules.mk b/lib/libc/string/arch/x86/rules.mk
new file mode 100644
index 0000000..b3a5aa9
--- /dev/null
+++ b/lib/libc/string/arch/x86/rules.mk
@@ -0,0 +1,11 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+ASM_STRING_OPS := #bcopy bzero memcpy memmove memset
+
+OBJS += \
+ #$(LOCAL_DIR)/memcpy.o \
+ #$(LOCAL_DIR)/memset.o
+
+# filter out the C implementation
+C_STRING_OPS := $(filter-out $(ASM_STRING_OPS),$(C_STRING_OPS))
+
diff --git a/lib/partition/partition.c b/lib/partition/partition.c
new file mode 100644
index 0000000..5565fe5
--- /dev/null
+++ b/lib/partition/partition.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <printf.h>
+#include <string.h>
+#include <compiler.h>
+#include <stdlib.h>
+#include <arch.h>
+#include <lib/bio.h>
+#include <lib/partition.h>
+
+struct chs {
+ uint8_t c;
+ uint8_t h;
+ uint8_t s;
+} __PACKED;
+
+struct mbr_part {
+ uint8_t status;
+ struct chs start;
+ uint8_t type;
+ struct chs end;
+ uint32_t lba_start;
+ uint32_t lba_length;
+} __PACKED;
+
+static status_t validate_mbr_partition(bdev_t *dev, const struct mbr_part *part)
+{
+ /* check for invalid types */
+ if (part->type == 0)
+ return -1;
+ /* check for invalid status */
+ if (part->status != 0x80 && part->status != 0x00)
+ return -1;
+
+ /* make sure the range fits within the device */
+ if (part->lba_start >= dev->block_count)
+ return -1;
+ if ((part->lba_start + part->lba_length) > dev->block_count)
+ return -1;
+
+ /* that's about all we can do, MBR has no other good way to see if it's valid */
+
+ return 0;
+}
+
+int partition_publish(const char *device, off_t offset)
+{
+ int err = 0;
+ int count = 0;
+
+ // clear any partitions that may have already existed
+ partition_unpublish(device);
+
+ bdev_t *dev = bio_open(device);
+ if (!dev) {
+ printf("partition_publish: unable to open device\n");
+ return -1;
+ }
+
+ // get a dma aligned and padded block to read info
+ STACKBUF_DMA_ALIGN(buf, dev->block_size);
+
+ /* sniff for MBR partition types */
+ do {
+ int i;
+
+ err = bio_read(dev, buf, offset, 512);
+ if (err < 0)
+ goto err;
+
+ /* look for the aa55 tag */
+ if (buf[510] != 0x55 || buf[511] != 0xaa)
+ break;
+
+ /* see if a partition table makes sense here */
+ struct mbr_part part[4];
+ memcpy(part, buf + 446, sizeof(part));
+
+#if DEBUGLEVEL >= INFO
+ dprintf(INFO, "mbr partition table dump:\n");
+ for (i=0; i < 4; i++) {
+ dprintf(INFO, "\t%i: status 0x%hhx, type 0x%hhx, start 0x%x, len 0x%x\n", i, part[i].status, part[i].type, part[i].lba_start, part[i].lba_length);
+ }
+#endif
+
+ /* validate each of the partition entries */
+ for (i=0; i < 4; i++) {
+ if (validate_mbr_partition(dev, &part[i]) >= 0) {
+ // publish it
+ char subdevice[128];
+
+ sprintf(subdevice, "%sp%d", device, i);
+
+ err = bio_publish_subdevice(device, subdevice, part[i].lba_start, part[i].lba_length);
+ if (err < 0) {
+ dprintf(INFO, "error publishing subdevice '%s'\n", subdevice);
+ continue;
+ }
+ count++;
+ }
+ }
+ } while(0);
+
+ bio_close(dev);
+
+err:
+ return (err < 0) ? err : count;
+}
+
+int partition_unpublish(const char *device)
+{
+ int i;
+ int count;
+ bdev_t *dev;
+ char devname[512];
+
+ count = 0;
+ for (i=0; i < 16; i++) {
+ sprintf(devname, "%sp%d", device, i);
+
+ dev = bio_open(devname);
+ if (!dev)
+ continue;
+
+ bio_unregister_device(dev);
+ bio_close(dev);
+ count++;
+ }
+
+ return count;
+}
+
diff --git a/lib/partition/rules.mk b/lib/partition/rules.mk
new file mode 100644
index 0000000..f80eb44
--- /dev/null
+++ b/lib/partition/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += lib/bio
+
+OBJS += \
+ $(LOCAL_DIR)/partition.o
diff --git a/lib/text/rules.mk b/lib/text/rules.mk
new file mode 100644
index 0000000..9555d00
--- /dev/null
+++ b/lib/text/rules.mk
@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += lib/font
+
+OBJS += \
+ $(LOCAL_DIR)/text.o
diff --git a/lib/text/text.c b/lib/text/text.c
new file mode 100644
index 0000000..4b5f4ca
--- /dev/null
+++ b/lib/text/text.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @addtogroup graphics
+ * @{
+ */
+
+/**
+ * @file
+ * @brief Console text display
+ *
+ * This module displays text on the console. The text is retained so that
+ * it can be redisplayed if the display is cleared.
+ *
+ * Output is to the default graphics display
+ */
+
+#include <debug.h>
+#include <list.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dev/display.h>
+#include <lib/gfx.h>
+#include <lib/font.h>
+#include <lib/text.h>
+
+#define TEXT_COLOR 0xffffffff
+
+static struct list_node text_list = LIST_INITIAL_VALUE(text_list);
+
+struct text_line {
+ struct list_node node;
+ const char *str;
+ int x, y;
+};
+
+/**
+ * @brief Add a string to the console text
+ */
+void text_draw(int x, int y, const char *string)
+{
+ struct text_line *line = malloc(sizeof(struct text_line));
+
+ line->str = strdup(string);
+ line->x = x;
+ line->y = y;
+
+ list_add_head(&text_list, &line->node);
+
+ text_update();
+}
+
+/**
+ * @brief Refresh the display
+ */
+void text_update(void)
+{
+ struct display_info info;
+ display_get_info(&info);
+
+ /* get the display's surface */
+ gfx_surface *surface = gfx_create_surface_from_display(&info);
+
+ struct text_line *line;
+ list_for_every_entry(&text_list, line, struct text_line, node) {
+ const char *c;
+ int x = line->x;
+ for (c = line->str; *c; c++) {
+ font_draw_char(surface, *c, x, line->y, TEXT_COLOR);
+ x += FONT_X;
+ }
+ }
+
+ gfx_flush(surface);
+
+ gfx_surface_destroy(surface);
+}
+
diff --git a/lib/tga/rules.mk b/lib/tga/rules.mk
new file mode 100644
index 0000000..8538f47
--- /dev/null
+++ b/lib/tga/rules.mk
@@ -0,0 +1,4 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+OBJS += \
+ $(LOCAL_DIR)/tga.o
diff --git a/lib/tga/tga.c b/lib/tga/tga.c
new file mode 100644
index 0000000..7b38ded
--- /dev/null
+++ b/lib/tga/tga.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @file
+ * @brief Parse tga format files
+ *
+ * @ingroup graphics
+ */
+
+#include <debug.h>
+#include <compiler.h>
+#include <lib/tga.h>
+
+#define LOCAL_TRACE 0
+
+struct tga_header {
+ uint8_t idlength;
+ uint8_t colormaptype;
+ uint8_t datatypecode;
+ uint16_t colormaporigin;
+ uint16_t colormaplength;
+ uint8_t colormapdepth;
+ uint16_t x_origin;
+ uint16_t y_origin;
+ uint16_t width;
+ uint16_t height;
+ uint8_t bitsperpixel;
+ uint8_t imagedescriptor;
+} __PACKED;
+
+static void print_tga_info(const struct tga_header *header)
+{
+ LTRACEF("idlength %hhd\n", header->idlength);
+ LTRACEF("colormaptype %hhd\n", header->colormaptype);
+ LTRACEF("datatypecode %hhd\n", header->datatypecode);
+ LTRACEF("colormaporigin %hd\n", header->colormaporigin);
+ LTRACEF("colormaplength %hd\n", header->colormaplength);
+ LTRACEF("colormapdepth %hhd\n", header->colormapdepth);
+ LTRACEF("x_origin %hd\n", header->x_origin);
+ LTRACEF("y_origin %hd\n", header->y_origin);
+ LTRACEF("width %hd\n", header->width);
+ LTRACEF("height %hd\n", header->height);
+ LTRACEF("bitsperpixel %hhd\n", header->bitsperpixel);
+ LTRACEF("imagedescriptor %hhd\n", header->imagedescriptor);
+
+}
+
+static void decode_2byte(gfx_surface *surface, uint x, uint y, const void *input)
+{
+ const uint8_t *in = (const uint8_t *)input;
+
+// printf("in 0x%hhx 0x%hhx\n", in[0], in[1]);
+ uint r,g,b;
+
+ b = (in[0] & 0x1f) << 3;
+ g = (((in[0] >> 5) & 0x7) | ((in[1] & 0x3) << 3)) << 3;
+ r = ((in[1] >> 2) & 0x1f) << 3;
+
+ gfx_putpixel(surface, x, y, 0xff000000 | r << 16 | g << 8 | b);
+}
+
+static void decode_3byte(gfx_surface *surface, uint x, uint y, const void *input)
+{
+ const uint8_t *in = (const uint8_t *)input;
+
+// printf("in 0x%hhx 0x%hhx\n", in[0], in[1]);
+
+ gfx_putpixel(surface, x, y, 0xff000000 | in[2] << 16 | in[1] << 8 | in[0]);
+}
+
+static void decode_4byte(gfx_surface *surface, uint x, uint y, const void *input)
+{
+ const uint8_t *in = (const uint8_t *)input;
+
+// printf("in 0x%hhx 0x%hhx 0x%hhx 0x%hhx\n", in[0], in[1], in[2], in[3]);
+
+ if (in[3] == 0)
+ gfx_putpixel(surface, x, y, 0);
+ else
+ gfx_putpixel(surface, x, y, in[3] << 24 | in[2] << 16 | in[1] << 8 | in[0]);
+}
+
+/**
+ * @brief Decode a tga image
+ *
+ * @param ptr Pointer to tga data in memory
+ * @param len Length of tga data
+ * @param format Desired format of returned graphics surface
+ *
+ * @return Graphics surface or NULL on error.
+ *
+ * @ingroup graphics
+ */
+gfx_surface *tga_decode(const void *ptr, size_t len, gfx_format format)
+{
+ const struct tga_header *header = (const struct tga_header *)ptr;
+
+ LTRACEF("ptr %p, len %zu\n", ptr, len);
+
+#if LOCAL_TRACE > 0
+ print_tga_info(header);
+#endif
+
+ /* do some sanity checks */
+ if (header->datatypecode != 2 && header->datatypecode != 10) {
+ dprintf(INFO, "tga_decode: unknown data type %d\n", header->datatypecode);
+ return NULL;
+ }
+ if (header->bitsperpixel != 16 && header->bitsperpixel != 24 && header->bitsperpixel != 32) {
+ dprintf(INFO, "tga_decode: unsupported bits per pixel %d\n", header->bitsperpixel);
+ return NULL;
+ }
+ if (header->colormaptype != 0) {
+ dprintf(INFO, "tga_decode: has colormap, can't handle\n");
+ return NULL;
+ }
+
+ const void *imagestart = ((const uint8_t *)ptr + sizeof(struct tga_header) + header->idlength);
+
+ /* create a surface to hold the decoded bits */
+ gfx_surface *surface = gfx_create_surface(NULL, header->width, header->height, header->width, format);
+ DEBUG_ASSERT(surface);
+
+ /* copy the bits out */
+ void (*decodefunc)(gfx_surface *, uint x, uint y, const void *) = NULL;
+
+ uint step = 1;
+ if (header->bitsperpixel == 16) {
+ step = 2;
+ decodefunc = decode_2byte;
+ } else if (header->bitsperpixel == 24) {
+ step = 3;
+ decodefunc = decode_3byte;
+ } else if (header->bitsperpixel == 32) {
+ step = 4;
+ decodefunc = decode_4byte;
+ }
+
+ if (header->datatypecode == 2) {
+ /* no RLE */
+ uint pos = 0;
+ uint x, y;
+ uint surfacey;
+
+ for (y = 0; y < header->height; y++) {
+
+ if ((header->imagedescriptor & (1 << 5)) == 0)
+ surfacey = (surface->height - 1) - y;
+ else
+ surfacey = y;
+
+ for (x = 0; x < header->width; x++) {
+ decodefunc(surface, x, surfacey, (const uint8_t *)imagestart + pos);
+ pos += step;
+ }
+ }
+ } else if (header->datatypecode == 10) {
+ /* RLE compression */
+ uint pos = 0;
+ uint count = 0;
+ uint x, y;
+
+ x = 0;
+ if ((header->imagedescriptor & (1 << 5)) == 0)
+ y = header->height - 1;
+ else
+ y = 0;
+
+ while (count < (uint)header->height * (uint)header->width) {
+ uint runpos;
+
+ uint8_t run = *((const uint8_t *)imagestart + pos);
+ bool repeat_run = (run & 0x80);
+ uint runlen = (run & 0x7f) + 1;
+
+// printf("pos 0x%x count %u run 0x%hhx runtype %d runlen %u\n", pos, count, run, run & 0x80, runlen);
+
+ /* consume the run byte */
+ pos++;
+
+ /* start of a run */
+ for (runpos = 0; runpos < runlen; runpos++) {
+ decodefunc(surface, x, y, (const uint8_t *)imagestart + pos);
+ count++;
+
+ x++;
+ if (x == surface->width) {
+ if ((header->imagedescriptor & (1 << 5)) == 0)
+ y--;
+ else
+ y++;
+ x = 0;
+ }
+
+ /* if a run of raw pixels, consume an input pixel */
+ if (!repeat_run)
+ pos += step;
+ }
+ /* if this was a run of repeated pixels, consume the one input pixel we repeated */
+ if (repeat_run)
+ pos += step;
+
+ }
+// printf("done with RLE: x %d, y %d, pos %d, count %d\n", x, y, pos, count);
+ }
+
+ return surface;
+}
+
diff --git a/makefile b/makefile
index f93bfd9..da8567d 100644
--- a/makefile
+++ b/makefile
@@ -1,3 +1,8 @@
+ifeq ($(MAKECMDGOALS),spotless)
+spotless:
+ rm -rf build-*
+else
+
-include local.mk
include make/macros.mk
@@ -155,9 +160,6 @@
clean: $(EXTRA_CLEANDEPS)
rm -f $(ALLOBJS) $(DEPS) $(GENERATED) $(OUTBIN) $(OUTELF) $(OUTELF).lst
-spotless:
- rm -rf build-*
-
install: all
scp $(OUTBIN) 192.168.0.4:/tftproot
@@ -194,3 +196,5 @@
.PHONY: configheader
endif
+
+endif # make spotless
diff --git a/platform/armemu/blkdev.c b/platform/armemu/blkdev.c
new file mode 100644
index 0000000..b5fbc43
--- /dev/null
+++ b/platform/armemu/blkdev.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <err.h>
+#include <debug.h>
+#include <platform.h>
+#include "platform_p.h"
+#include <platform/armemu.h>
+#include <lib/bio.h>
+#include <reg.h>
+
+static bdev_t dev;
+
+static uint64_t get_blkdev_len(void)
+{
+ return *REG64(BDEV_LEN);
+}
+
+ssize_t read_block(struct bdev *dev, void *buf, bnum_t block, uint count)
+{
+ /* assume args have been validated by layer above */
+ *REG32(BDEV_CMD_ADDR) = (uint32_t)buf;
+ *REG64(BDEV_CMD_OFF) = (uint64_t)((uint64_t)block * dev->block_size);
+ *REG32(BDEV_CMD_LEN) = count * dev->block_size;
+
+ *REG32(BDEV_CMD) = BDEV_CMD_READ;
+
+ uint32_t err = *REG32(BDEV_CMD) & BDEV_CMD_ERRMASK;
+ if (err == BDEV_CMD_ERR_NONE)
+ return count * dev->block_size;
+ else
+ return ERR_IO;
+}
+
+ssize_t write_block(struct bdev *dev, const void *buf, bnum_t block, uint count)
+{
+ /* assume args have been validated by layer above */
+ *REG32(BDEV_CMD_ADDR) = (uint32_t)buf;
+ *REG64(BDEV_CMD_OFF) = (uint64_t)((uint64_t)block * dev->block_size);
+ *REG32(BDEV_CMD_LEN) = count * dev->block_size;
+
+ *REG32(BDEV_CMD) = BDEV_CMD_WRITE;
+
+ uint32_t err = *REG32(BDEV_CMD) & BDEV_CMD_ERRMASK;
+ if (err == BDEV_CMD_ERR_NONE)
+ return count * dev->block_size;
+ else
+ return ERR_IO;
+}
+
+void platform_init_blkdev(void)
+{
+ if ((*REG32(SYSINFO_FEATURES) & SYSINFO_FEATURE_BLOCKDEV) == 0)
+ return; // no block device
+
+ TRACEF("device len %lld\n", get_blkdev_len());
+
+ if (get_blkdev_len() == 0)
+ return;
+
+ bio_initialize_bdev(&dev, "block0", 512, get_blkdev_len() / 512);
+
+ // fill in hooks
+ dev.read_block = &read_block;
+ dev.write_block = &write_block;
+
+ bio_register_device(&dev);
+}
+
diff --git a/platform/armemu/debug.c b/platform/armemu/debug.c
index 09aabd5..9eea536 100644
--- a/platform/armemu/debug.c
+++ b/platform/armemu/debug.c
@@ -32,15 +32,21 @@
*REG8(DEBUG_STDOUT) = c;
}
-int dgetc(char *c)
+int dgetc(char *c, bool wait)
{
- int8_t result = (int8_t)*REG8(DEBUG_STDIN);
+ for (;;) {
+ int8_t result = (int8_t)*REG8(DEBUG_STDIN);
- if (result == -1)
- return -1;
+ if (result == -1) {
+ if (wait)
+ continue;
+ else
+ return -1;
+ }
- *c = (char)result;
- return 0;
+ *c = (char)result;
+ return 0;
+ }
}
void debug_dump_regs(void)
diff --git a/platform/armemu/display.c b/platform/armemu/display.c
new file mode 100644
index 0000000..5b33965
--- /dev/null
+++ b/platform/armemu/display.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <err.h>
+#include <debug.h>
+#include <platform.h>
+#include "platform_p.h"
+#include <platform/armemu.h>
+#include <dev/display.h>
+#include <lib/gfx.h>
+#include <reg.h>
+
+static int display_w, display_h;
+static void *display_fb;
+
+inline static int has_display(void)
+{
+ return *REG32(SYSINFO_FEATURES) & SYSINFO_FEATURE_DISPLAY;
+}
+
+void platform_init_display(void)
+{
+ if (!has_display())
+ return;
+
+ display_fb = (void *)DISPLAY_FRAMEBUFFER;
+ display_w = *REG32(DISPLAY_WIDTH);
+ display_h = *REG32(DISPLAY_HEIGHT);
+
+ gfx_draw_pattern();
+}
+
+void display_get_info(struct display_info *info)
+{
+ if (!has_display())
+ return;
+
+ info->framebuffer = display_fb;
+ info->format = GFX_FORMAT_RGB_x888;
+ info->width = display_w;
+ info->height = display_h;
+ info->stride = display_w;
+ info->flush = NULL;
+}
+
diff --git a/platform/armemu/include/platform/armemu/memmap.h b/platform/armemu/include/platform/armemu/memmap.h
index 9df4e0b..b13050f 100644
--- a/platform/armemu/include/platform/armemu/memmap.h
+++ b/platform/armemu/include/platform/armemu/memmap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2006 Travis Geiselbrecht
+ * Copyright (c) 2005-2010 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -45,6 +45,7 @@
#define SYSINFO_FEATURE_DISPLAY 0x00000001
#define SYSINFO_FEATURE_CONSOLE 0x00000002
#define SYSINFO_FEATURE_NETWORK 0x00000004
+#define SYSINFO_FEATURE_BLOCKDEV 0x00000008
/* a write to this register latches the current emulator system time, so the next two regs can be read atomically */
#define SYSINFO_TIME_LATCH (SYSINFO_REGS_BASE + 4)
@@ -58,7 +59,10 @@
#define DISPLAY_FRAMEBUFFER DISPLAY_BASE
#define DISPLAY_REGS_BASE (DISPLAY_BASE + DISPLAY_SIZE)
#define DISPLAY_REGS_SIZE MEMBANK_SIZE
- /* no display regs for now */
+
+#define DISPLAY_WIDTH (DISPLAY_REGS_BASE + 0) // pixels width/height read/only
+#define DISPLAY_HEIGHT (DISPLAY_REGS_BASE + 4)
+#define DISPLAY_BPP (DISPLAY_REGS_BASE + 8) // bits per pixel (16/32)
/* console (keyboard controller */
#define CONSOLE_REGS_BASE (DISPLAY_REGS_BASE + DISPLAY_REGS_SIZE)
@@ -145,4 +149,27 @@
#define NET_IN_BUF_LEN (NET_REGS_BASE + 16) /* length of the currently selected in buffer, via tail register */
#define NET_IN_BUF (NET_REGS_BASE + NET_BUF_LEN*2)
+/* block device interface */
+#define BDEV_REGS_BASE (NET_REGS_BASE + NET_REGS_SIZE)
+#define BDEV_REGS_SIZE MEMBANK_SIZE
+
+#define BDEV_CMD (BDEV_REGS_BASE + 0) /* command */
+#define BDEV_CMD_ADDR (BDEV_REGS_BASE + 4) /* address of next transfer, 32bit */
+#define BDEV_CMD_OFF (BDEV_REGS_BASE + 8) /* offset of next transfer, 64bit */
+#define BDEV_CMD_LEN (BDEV_REGS_BASE + 16) /* length of next transfer, 32bit */
+
+#define BDEV_LEN (BDEV_REGS_BASE + 20) /* length of block device, 64bit */
+
+/* BDEV_CMD bits */
+#define BDEV_CMD_MASK (0x3)
+#define BDEV_CMD_NOP (0)
+#define BDEV_CMD_READ (1)
+#define BDEV_CMD_WRITE (2)
+#define BDEV_CMD_ERASE (3)
+#define BDEV_CMD_ERRSHIFT 16
+#define BDEV_CMD_ERRMASK (0xffff << BDEV_CMD_ERRSHIFT)
+#define BDEV_CMD_ERR_NONE (0 << BDEV_CMD_ERRSHIFT)
+#define BDEV_CMD_ERR_GENERAL (1 << BDEV_CMD_ERRSHIFT)
+#define BDEV_CMD_ERR_BAD_OFFSET (2 << BDEV_CMD_ERRSHIFT)
+
#endif
diff --git a/platform/armemu/platform.c b/platform/armemu/platform.c
index 1425674..0076b57 100644
--- a/platform/armemu/platform.c
+++ b/platform/armemu/platform.c
@@ -40,5 +40,7 @@
void platform_init(void)
{
+ platform_init_blkdev();
+ platform_init_display();
}
diff --git a/platform/armemu/platform_p.h b/platform/armemu/platform_p.h
index 872ea2b..28f7210 100644
--- a/platform/armemu/platform_p.h
+++ b/platform/armemu/platform_p.h
@@ -25,6 +25,8 @@
void platform_init_interrupts(void);
void platform_init_timer(void);
+void platform_init_blkdev(void);
+void platform_init_display(void);
#endif
diff --git a/platform/armemu/rules.mk b/platform/armemu/rules.mk
index 13543f4..9910960 100644
--- a/platform/armemu/rules.mk
+++ b/platform/armemu/rules.mk
@@ -15,11 +15,20 @@
$(LOCAL_DIR)/interrupts.o \
$(LOCAL_DIR)/platform.o \
$(LOCAL_DIR)/timer.o \
+ $(LOCAL_DIR)/blkdev.o \
+ $(LOCAL_DIR)/display.o \
# $(LOCAL_DIR)/console.o \
$(LOCAL_DIR)/net.o \
+DEFINES += \
+ WITH_DEV_DISPLAY=1
+
+MODULES += \
+ lib/gfx
+
+
MEMBASE := 0x0
MEMSIZE := 0x400000 # 4MB
diff --git a/platform/armemu/timer.c b/platform/armemu/timer.c
index 4d209a4..4cc2b50 100644
--- a/platform/armemu/timer.c
+++ b/platform/armemu/timer.c
@@ -48,13 +48,23 @@
return NO_ERROR;
}
+bigtime_t current_time_hires(void)
+{
+ bigtime_t time;
+ *REG(SYSINFO_TIME_LATCH) = 1;
+ time = *REG(SYSINFO_TIME_SECS) * 1000000ULL;
+ time += *REG(SYSINFO_TIME_USECS);
+
+ return time;
+}
+
time_t current_time(void)
{
time_t time;
*REG(SYSINFO_TIME_LATCH) = 1;
time = *REG(SYSINFO_TIME_SECS) * 1000;
time += *REG(SYSINFO_TIME_USECS) / 1000;
-
+
return time;
}
diff --git a/platform/at91sam7/debug.c b/platform/at91sam7/debug.c
index ad8f262..5520a21 100644
--- a/platform/at91sam7/debug.c
+++ b/platform/at91sam7/debug.c
@@ -64,6 +64,12 @@
}
}
+int dgetc(char *c, bool wait)
+{
+ return -1;
+}
+
+
void _dputc(char c)
{
ser_putc(c);
@@ -75,7 +81,3 @@
for(;;);
}
-uint32_t debug_cycle_count()
-{
- PANIC_UNIMPLEMENTED;
-}
diff --git a/platform/at91sam7/timer.c b/platform/at91sam7/timer.c
index be65e9c..8e2c6e3 100644
--- a/platform/at91sam7/timer.c
+++ b/platform/at91sam7/timer.c
@@ -48,6 +48,11 @@
return ticks;
}
+bigtime_t current_time_hires(void)
+{
+ return ticks * 1000ULL;
+}
+
static enum handler_return pit_irq_handler(void *arg)
{
AT91PIT *pit = AT91PIT_ADDR;
diff --git a/platform/integrator/debug.c b/platform/integrator/debug.c
index 0a2e058..f8f456c 100644
--- a/platform/integrator/debug.c
+++ b/platform/integrator/debug.c
@@ -98,7 +98,7 @@
uart_putc(0, c);
}
-int dgetc(char *c)
+int dgetc(char *c, bool wait)
{
int result = uart_getc(0, false);
@@ -140,7 +140,3 @@
PANIC_UNIMPLEMENTED;
}
-uint32_t debug_cycle_count()
-{
- PANIC_UNIMPLEMENTED;
-}
diff --git a/platform/msm7x30/acpuclock.c b/platform/msm7x30/acpuclock.c
index c6aae9c..af16c88 100644
--- a/platform/msm7x30/acpuclock.c
+++ b/platform/msm7x30/acpuclock.c
@@ -320,7 +320,7 @@
}
}
-void ce_enable_clock(void)
+void ce_clock_init(void)
{
unsigned int val=0;
diff --git a/platform/msm7x30/platform.c b/platform/msm7x30/platform.c
index 79c6a1d..5916866 100644
--- a/platform/msm7x30/platform.c
+++ b/platform/msm7x30/platform.c
@@ -88,7 +88,6 @@
dprintf(INFO, "platform_init()\n");
acpu_clock_init();
adm_enable_clock();
- ce_enable_clock();
}
void mdp4_display_intf_sel(int output, int intf)
diff --git a/platform/msm8960/acpuclock.c b/platform/msm8960/acpuclock.c
index 404bee2..1deed72 100644
--- a/platform/msm8960/acpuclock.c
+++ b/platform/msm8960/acpuclock.c
@@ -257,3 +257,13 @@
reg |= MMC_BOOT_MCI_CLK_IN_FEEDBACK;
writel( reg, MMC_BOOT_MCI_CLK );
}
+
+/* Configure crypto engine clock */
+void ce_clock_init(void)
+{
+ /* Enable HCLK for CE1 */
+ writel((1<<4), CE1_HCLK_CTL);
+ /* Enable core clk for CE1 */
+ writel((1<<4), CE1_CORE_CLK_CTL);
+ return;
+}
diff --git a/platform/msm8960/include/platform/iomap.h b/platform/msm8960/include/platform/iomap.h
index e72efd6..04f15e0 100644
--- a/platform/msm8960/include/platform/iomap.h
+++ b/platform/msm8960/include/platform/iomap.h
@@ -105,6 +105,8 @@
#define GSBIn_UART_APPS_NS(n) (CLK_CTL_BASE + 0x29D4 + (32 * ((n) - 1)))
#define MSM_BOOT_PLL8_STATUS (CLK_CTL_BASE + 0x3158)
#define MSM_BOOT_PLL_ENABLE_SC0 (CLK_CTL_BASE + 0x34C0)
+#define CE1_HCLK_CTL (CLK_CTL_BASE + 0x2720)
+#define CE1_CORE_CLK_CTL (CLK_CTL_BASE + 0x2724)
#define MSM_MMSS_CLK_CTL_BASE 0x04000000
@@ -137,4 +139,6 @@
//TODO: Where does this go?
#define MMSS_SFPB_GPREG (0x05700058)
+#define CE1_CRYPTO4_BASE (0x18500000)
+#define MSM_CRYPTO_BASE CE1_CRYPTO4_BASE
#endif
diff --git a/platform/msm8x60/platform.c b/platform/msm8x60/platform.c
index cc17781..1f08c2b 100644
--- a/platform/msm8x60/platform.c
+++ b/platform/msm8x60/platform.c
@@ -117,7 +117,6 @@
void platform_init(void)
{
dprintf(INFO, "platform_init()\n");
- ce_clock_init();
}
void display_init(void)
diff --git a/platform/msm_shared/crypto4_eng.c b/platform/msm_shared/crypto4_eng.c
new file mode 100644
index 0000000..59562c4
--- /dev/null
+++ b/platform/msm_shared/crypto4_eng.c
@@ -0,0 +1,355 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <endian.h>
+#include <debug.h>
+#include <reg.h>
+#include <bits.h>
+#include <platform/iomap.h>
+#include <crypto4_eng.h>
+#include <crypto_hash.h>
+
+extern void dsb(void);
+
+/*
+ * Function to reset the crypto engine.
+ */
+
+void crypto_eng_reset(void)
+{
+ return;
+}
+
+/*
+ * Function to initialize the crypto engine for a new session. It enables the
+ * auto shutdown feature of CRYPTO and mask various interrupts since we use
+ * polling. We are not using DMOV now.
+ */
+
+void crypto_eng_init(void)
+{
+ unsigned int val;
+ val = (AUTO_SHUTDOWN_EN | MASK_ERR_INTR | MASK_DIN_INTR |
+ MASK_DOUT_INTR | HIGH_SPD_IN_EN_N | HIGH_SPD_OUT_EN_N);
+
+ val |= MASK_OP_DONE_INTR;
+
+ wr_ce(val,CRYPTO_CONFIG);
+}
+
+/*
+ * Function to set various SHAx registers in CRYPTO based on algorithm type.
+ */
+
+void crypto_set_sha_ctx(void *ctx_ptr, unsigned int bytes_to_write,
+ crypto_auth_alg_type auth_alg, bool first, bool last)
+{
+ crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx*)ctx_ptr;
+ crypto_SHA256_ctx *sha256_ctx = (crypto_SHA256_ctx*)ctx_ptr;
+ unsigned int i=0;
+ unsigned int iv_len=0;
+ unsigned int *auth_iv;
+ unsigned int seg_cfg_val;
+
+ seg_cfg_val = SEG_CFG_AUTH_ALG_SHA;
+
+ if(auth_alg == CRYPTO_AUTH_ALG_SHA1)
+ {
+ seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA1;
+
+ if(last)
+ {
+ seg_cfg_val |= SEG_CFG_LAST;
+ }
+
+ iv_len = SHA1_INIT_VECTOR_SIZE;
+ auth_iv = sha1_ctx->auth_iv;
+ }
+ else if(auth_alg == CRYPTO_AUTH_ALG_SHA256)
+ {
+ seg_cfg_val |= SEG_CFG_AUTH_SIZE_SHA256;
+
+ if(last)
+ {
+ seg_cfg_val |= SEG_CFG_LAST;
+ }
+
+ iv_len = SHA256_INIT_VECTOR_SIZE;
+ auth_iv = sha256_ctx->auth_iv;
+ }
+ else
+ {
+ dprintf(CRITICAL, "crypto_set_sha_ctx invalid auth algorithm\n");
+ return;
+ }
+
+ for(i=0; i<iv_len; i++)
+ {
+ wr_ce(*(auth_iv+i),CRYPTO_AUTH_IVn(i));
+ }
+ wr_ce(seg_cfg_val,CRYPTO_AUTH_SEG_CFG);
+
+ /* Typecast with crypto_SHA1_ctx because offset of auth_bytecnt in both
+ crypto_SHA1_ctx and crypto_SHA256_ctx are same */
+
+ wr_ce(((crypto_SHA1_ctx*)ctx_ptr)->auth_bytecnt[0],CRYPTO_AUTH_BYTECNTn(0));
+ wr_ce(((crypto_SHA1_ctx*)ctx_ptr)->auth_bytecnt[1],CRYPTO_AUTH_BYTECNTn(1));
+
+ wr_ce(bytes_to_write,CRYPTO_AUTH_SEG_SIZE);
+
+ wr_ce(bytes_to_write,CRYPTO_SEG_SIZE);
+
+ /*
+ * Ensure previous instructions (any writes to config registers)
+ * are completed.
+ *
+ * TODO: Revisit dsb.
+ */
+ dsb();
+
+ wr_ce(GOPROC_GO,CRYPTO_GOPROC);
+
+ return;
+}
+
+/*
+ * Function to send data to CRYPTO. This is non-DMOV implementation and uses
+ * polling to send the requested amount of data.
+ */
+
+void crypto_send_data(void *ctx_ptr, unsigned char *data_ptr,
+ unsigned int buff_size, unsigned int bytes_to_write,
+ unsigned int *ret_status)
+{
+ crypto_SHA1_ctx *sha1_ctx = (crypto_SHA1_ctx*)ctx_ptr;
+ unsigned int bytes_left=0;
+ unsigned int i=0;
+ unsigned int ce_status=0;
+ unsigned int ce_err_bmsk=0;
+ unsigned int is_not_aligned=FALSE;
+ unsigned char data[4];
+ unsigned char *buff_ptr=data_ptr;
+
+ /* Check if the buff_ptr is aligned */
+ if(!(IS_ALIGNED(buff_ptr)))
+ {
+ is_not_aligned = TRUE;
+ }
+
+ /* Fill the saved_buff with data from buff_ptr. First we have to write
+ all the data from the saved_buff and then we will write data from
+ buff_ptr. We will update bytes_left and buff_ptr in the while loop
+ once are done writing all the data from saved_buff. */
+
+ if(sha1_ctx->saved_buff_indx != 0)
+ {
+ memcpy(sha1_ctx->saved_buff + sha1_ctx->saved_buff_indx, buff_ptr,
+ (((buff_size + sha1_ctx->saved_buff_indx) <= CRYPTO_SHA_BLOCK_SIZE)
+ ? buff_size : (CRYPTO_SHA_BLOCK_SIZE - sha1_ctx->saved_buff_indx)));
+
+ if(bytes_to_write >= CRYPTO_SHA_BLOCK_SIZE)
+ {
+ bytes_left = CRYPTO_SHA_BLOCK_SIZE;
+ }
+ else
+ {
+ bytes_left = bytes_to_write;
+ }
+ }
+ else
+ {
+ bytes_left = bytes_to_write;
+ }
+
+ /* Error bitmask to check crypto engine status */
+ ce_err_bmsk = (SW_ERR | DIN_RDY | DIN_SIZE_AVAIL);
+
+ while(bytes_left >= 4)
+ {
+ ce_status = rd_ce(CRYPTO_STATUS);
+ ce_status &= ce_err_bmsk;
+
+ if(ce_status & SW_ERR)
+ {
+ /* If there is SW_ERR, reset the engine */
+ crypto_eng_reset();
+ *ret_status = CRYPTO_ERR_FAIL;
+ dprintf(CRITICAL, "crypto_send_data sw error\n");
+ return;
+ }
+
+ /* We can write data now - 4 bytes at a time in network byte order */
+ if((ce_status & DIN_RDY) && ((ce_status & DIN_SIZE_AVAIL) >= 4))
+ {
+ if(sha1_ctx->saved_buff_indx != 0)
+ {
+ /* Write from saved_buff */
+ wr_ce(htonl(*((unsigned int *)(sha1_ctx->saved_buff)+i)),CRYPTO_DATA_IN);
+ }
+ else
+ {
+ if(!is_not_aligned)
+ {
+ /* Write from buff_ptr aligned */
+ wr_ce(htonl(*((unsigned int *)buff_ptr+i)),CRYPTO_DATA_IN);
+ }
+ else
+ {
+ /* If buff_ptr is not aligned write byte by byte */
+ data[0] = *(buff_ptr+i);
+ data[1] = *(buff_ptr+i+1);
+ data[2] = *(buff_ptr+i+2);
+ data[3] = *(buff_ptr+i+3);
+ /* i will incremented by 1 in outside block */
+ i+=3;
+ wr_ce(htonl(*(unsigned int *)data),CRYPTO_DATA_IN);
+ memset(data,0,4);
+ }
+ }
+ i++;
+ bytes_left -=4;
+
+ /* Check if we have written from saved_buff. Adjust buff_ptr and
+ bytes_left accordingly */
+ if((sha1_ctx->saved_buff_indx != 0) && (bytes_left == 0) &&
+ (bytes_to_write > CRYPTO_SHA_BLOCK_SIZE))
+ {
+ bytes_left = (bytes_to_write - CRYPTO_SHA_BLOCK_SIZE);
+ buff_ptr = (unsigned char *)((unsigned char *)data_ptr +
+ CRYPTO_SHA_BLOCK_SIZE - sha1_ctx->saved_buff_indx);
+ i = 0;
+ sha1_ctx->saved_buff_indx = 0;
+ if(!(IS_ALIGNED(buff_ptr)))
+ {
+ is_not_aligned = TRUE;
+ }
+ }
+ }
+ }
+
+ /* We might have bytes_left < 4. Write them now if available */
+ if(bytes_left)
+ {
+ memset(data,0,sizeof(unsigned int));
+
+ if(sha1_ctx->saved_buff_indx)
+ buff_ptr = (sha1_ctx->saved_buff + bytes_to_write - 1);
+ else
+ buff_ptr = (((unsigned char *)data_ptr) + buff_size - 1);
+
+ for(i=0;i<bytes_left;i++)
+ {
+ data[3-i] = *(buff_ptr-bytes_left+i+1);
+ }
+
+ ce_status = rd_ce(CRYPTO_STATUS);
+ ce_status &= ce_err_bmsk;
+
+ if(ce_status & SW_ERR)
+ {
+ crypto_eng_reset();
+ *ret_status = CRYPTO_ERR_FAIL;
+ dprintf(CRITICAL, "crypto_send_data sw error 2\n");
+ return;
+ }
+ if((ce_status & DIN_RDY) && ((ce_status & DIN_SIZE_AVAIL) >= 4))
+ {
+ wr_ce(*(unsigned int *)data,CRYPTO_DATA_IN);
+ }
+ }
+ *ret_status = CRYPTO_ERR_NONE;
+ return;
+}
+
+/*
+ * Function to get digest from CRYPTO. We poll for AUTH_DONE from CRYPTO.
+ */
+
+void crypto_get_digest(unsigned char *digest_ptr, unsigned int *ret_status,
+ crypto_auth_alg_type auth_alg, bool last)
+{
+ unsigned int ce_status=0;
+ unsigned int ce_err_bmsk=0;
+ unsigned int i=0;
+ unsigned int digest_len=0;
+
+ ce_err_bmsk = (OPERATION_DONE | SW_ERR);
+
+ do
+ {
+ ce_status = rd_ce(CRYPTO_STATUS);
+ ce_status &= ce_err_bmsk;
+ }while (ce_status == 0);
+
+ if(ce_status & SW_ERR)
+ {
+ crypto_eng_reset();
+ *ret_status = CRYPTO_ERR_FAIL;
+ dprintf(CRITICAL, "crypto_get_digest sw error\n");
+ return;
+ }
+
+ /* Digest length depends on auth_alg */
+
+ if(auth_alg == CRYPTO_AUTH_ALG_SHA1)
+ {
+ digest_len = SHA1_INIT_VECTOR_SIZE;
+ }
+ else if (auth_alg == CRYPTO_AUTH_ALG_SHA256)
+ {
+ digest_len = SHA256_INIT_VECTOR_SIZE;
+ }
+
+ /* Retrieve digest from CRYPTO */
+
+ for(i=0; i < digest_len;i++)
+ {
+ unsigned int auth_iv = rd_ce(CRYPTO_AUTH_IVn(i));
+
+ if(last)
+ {
+ *((unsigned int *)digest_ptr + i) = htonl(auth_iv);
+ }
+ else
+ {
+ *((unsigned int *)digest_ptr + i) = auth_iv;
+ }
+ }
+ *ret_status = CRYPTO_ERR_NONE;
+ return;
+}
+
+/* Function to restore auth_bytecnt registers for ctx_ptr */
+
+void crypto_get_ctx(void *ctx_ptr)
+{
+ ((crypto_SHA1_ctx*)ctx_ptr)->auth_bytecnt[0] = rd_ce(CRYPTO_AUTH_BYTECNTn(0));
+ ((crypto_SHA1_ctx*)ctx_ptr)->auth_bytecnt[1] = rd_ce(CRYPTO_AUTH_BYTECNTn(1));
+ return;
+}
diff --git a/platform/msm_shared/crypto_hash.c b/platform/msm_shared/crypto_hash.c
index 21c15ec..bf869f5 100644
--- a/platform/msm_shared/crypto_hash.c
+++ b/platform/msm_shared/crypto_hash.c
@@ -30,12 +30,13 @@
#include <debug.h>
#include <sys/types.h>
#include "crypto_hash.h"
-#include "crypto_eng.h"
static crypto_SHA256_ctx g_sha256_ctx;
static crypto_SHA1_ctx g_sha1_ctx;
static unsigned char crypto_init_done = FALSE;
+extern void ce_clock_init(void);
+
/*
* Top level function which calculates SHAx digest with given data and size.
* Digest varies based on the authentication algorithm.
@@ -71,6 +72,7 @@
{
if(crypto_init_done != TRUE)
{
+ ce_clock_init();
crypto_eng_reset();
crypto_init_done = TRUE;
}
diff --git a/platform/msm_shared/debug.c b/platform/msm_shared/debug.c
index 935d886..9adc4e4 100644
--- a/platform/msm_shared/debug.c
+++ b/platform/msm_shared/debug.c
@@ -55,7 +55,7 @@
#endif
}
-int dgetc(char *c)
+int dgetc(char *c, bool wait)
{
int n;
#if WITH_DEBUG_DCC
diff --git a/platform/msm_shared/include/crypto4_eng.h b/platform/msm_shared/include/crypto4_eng.h
new file mode 100644
index 0000000..8046a67
--- /dev/null
+++ b/platform/msm_shared/include/crypto4_eng.h
@@ -0,0 +1,80 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __CRYPTO4_ENG_H__
+#define __CRYPYO4_ENG_H__
+
+#define CRYPTO_ENG_REG(offset) (MSM_CRYPTO_BASE + offset)
+
+#define wr_ce(val,reg) writel(val,CRYPTO_ENG_REG(reg))
+#define rd_ce(reg) readl(CRYPTO_ENG_REG(reg))
+
+#define IS_ALIGNED(ptr) (!(((unsigned int)ptr) & 0x03))
+
+/* CRYPTO4 registers */
+#define CRYPTO_DATA_IN 0x0008
+#define CRYPTO_DATA_OUT 0x0010
+#define CRYPTO_STATUS 0x0100
+#define CRYPTO_CONFIG 0x0500
+#define CRYPTO_DEBUG 0x0508
+#define CRYPTO_ENCR_SEG_CFG 0x0300
+#define CRYPTO_SEG_SIZE 0x0200
+#define CRYPTO_GOPROC 0x0204
+#define CRYPTO_ENGINES_AVAIL 0x0104
+#define CRYPTO_AUTH_SEG_CFG 0x0400
+#define CRYPTO_AUTH_SEG_SIZE 0x0404
+#define CRYPTO_AUTH_SEG_START 0x0408
+
+#define CRYPTO_AUTH_BYTECNTn(n) (0x04A0 + 4*(n))
+#define CRYPTO_AUTH_IVn(n) (0x0450 + 4*(n))
+
+
+/* Register bit definitions */
+#define SW_ERR BIT(0)
+#define OPERATION_DONE BIT(1)
+#define DIN_RDY BIT(2)
+#define DIN_SIZE_AVAIL 0x00380000
+
+/* CRYPTO_CONFIG register bit definitions */
+#define AUTO_SHUTDOWN_EN BIT(2)
+#define MASK_ERR_INTR BIT(3)
+#define MASK_OP_DONE_INTR BIT(4)
+#define MASK_DIN_INTR BIT(5)
+#define MASK_DOUT_INTR BIT(6)
+#define HIGH_SPD_IN_EN_N BIT(13)
+#define HIGH_SPD_OUT_EN_N BIT(14)
+
+/* CRYPTO_AUTH_SEG_CFG register bit definitions */
+#define SEG_CFG_AUTH_ALG_SHA (1<<0)
+#define SEG_CFG_AUTH_SIZE_SHA1 (0<<9)
+#define SEG_CFG_AUTH_SIZE_SHA256 (1<<9)
+#define SEG_CFG_LAST (1<<14)
+
+#define GOPROC_GO 1
+
+#endif
diff --git a/platform/msm_shared/include/crypto_hash.h b/platform/msm_shared/include/crypto_hash.h
index 4f3c992..2f9af3c 100644
--- a/platform/msm_shared/include/crypto_hash.h
+++ b/platform/msm_shared/include/crypto_hash.h
@@ -42,6 +42,9 @@
#define CRYPTO_SHA_BLOCK_SIZE 64
#define CRYPTO_MAX_AUTH_BLOCK_SIZE 0xFA00
+#define CRYPTO_ERR_NONE 0x01
+#define CRYPTO_ERR_FAIL 0x02
+
typedef enum {
CRYPTO_SHA_ERR_NONE,
CRYPTO_SHA_ERR_BUSY,
diff --git a/platform/msm_shared/include/mmc.h b/platform/msm_shared/include/mmc.h
index 8b9bdc6..bce4d0e 100644
--- a/platform/msm_shared/include/mmc.h
+++ b/platform/msm_shared/include/mmc.h
@@ -548,37 +548,9 @@
#define BINARY_IN_TABLE_SIZE (16 * 512)
#define MAX_FILE_ENTRIES 20
-#define MMC_EBR_TYPE 0x05
-#define MMC_MODEM_TYPE 0x06
-#define MMC_MODEM_TYPE2 0x0C
-#define MMC_SBL1_TYPE 0x4D
-#define MMC_SBL2_TYPE 0x51
-#define MMC_SBL3_TYPE 0x45
-#define MMC_RPM_TYPE 0x47
-#define MMC_TZ_TYPE 0x46
-#define MMC_MODEM_ST1_TYPE 0x4A
-#define MMC_MODEM_ST2_TYPE 0x4B
-#define MMC_EFS2_TYPE 0x4E
-
-#define MMC_ABOOT_TYPE 0x4C
-#define MMC_BOOT_TYPE 0x48
-#define MMC_SYSTEM_TYPE 0x82
-#define MMC_USERDATA_TYPE 0x83
-#define MMC_RECOVERY_TYPE 0x60
-#define MMC_MISC_TYPE 0x63
-
-#define MMC_PROTECTED_TYPE 0xEE
-
#define MMC_RCA 2
-struct mbr_entry
-{
- unsigned dstatus;
- unsigned dtype ;
- unsigned dfirstsec;
- unsigned dsize;
- unsigned char name[64];
-};
+extern unsigned gpt_partitions_exist;
/* Can be used to unpack array of upto 32 bits data */
#define UNPACK_BITS(array, start, len, size_of) \
@@ -625,8 +597,6 @@
unsigned int* out );
unsigned int mmc_write (unsigned long long data_addr,
unsigned int data_len, unsigned int* in);
-unsigned long long mmc_ptn_offset (unsigned char * name);
-unsigned long long mmc_ptn_size (unsigned char * name);
unsigned int mmc_read (unsigned long long data_addr, unsigned int* out,
unsigned int data_len);
@@ -639,8 +609,8 @@
unsigned int *in );
unsigned int mmc_write_partition (unsigned size, unsigned char *partition);
-
-void mmc_dump_partition_info();
+unsigned int mmc_write_mbr_in_blocks(unsigned size, unsigned char *mbrImage);
+unsigned int mmc_write_mbr(unsigned size, unsigned char *mbrImage);
#endif
diff --git a/platform/msm_shared/include/partition_parser.h b/platform/msm_shared/include/partition_parser.h
index 56855e2..fa90044 100644
--- a/platform/msm_shared/include/partition_parser.h
+++ b/platform/msm_shared/include/partition_parser.h
@@ -26,15 +26,19 @@
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* Lookup Type */
-//TODO: Remove when merging MBR code to mmc_parser
-#define PTN_OFFSET 0x01
-#define PTN_SIZE 0x02
+#define INVALID_PTN -1
+
+#define PARTITION_TYPE_MBR 0
+#define PARTITION_TYPE_GPT 1
+#define PARTITION_TYPE_GPT_BACKUP 2
/* GPT Signature should be 0x5452415020494645 */
#define GPT_SIGNATURE_1 0x54524150
#define GPT_SIGNATURE_2 0x20494645
+#define MMC_MBR_SIGNATURE_BYTE_0 0x55
+#define MMC_MBR_SIGNATURE_BYTE_1 0xAA
+
/* GPT Offsets */
#define PROTECTIVE_MBR_SIZE 512
#define PARTITION_TABLE_SIZE 512
@@ -57,7 +61,44 @@
#define MAX_GPT_NAME_SIZE 72
#define PARTITION_TYPE_GUID_SIZE 16
#define UNIQUE_PARTITION_GUID_SIZE 16
-#define NUM_GPT_PARTITIONS 32
+#define NUM_PARTITIONS 32
+
+/* Some useful define used to access the MBR/EBR table */
+#define BLOCK_SIZE 0x200
+#define TABLE_ENTRY_0 0x1BE
+#define TABLE_ENTRY_1 0x1CE
+#define TABLE_ENTRY_2 0x1DE
+#define TABLE_ENTRY_3 0x1EE
+#define TABLE_SIGNATURE 0x1FE
+#define TABLE_ENTRY_SIZE 0x010
+
+#define OFFSET_STATUS 0x00
+#define OFFSET_TYPE 0x04
+#define OFFSET_FIRST_SEC 0x08
+#define OFFSET_SIZE 0x0C
+#define COPYBUFF_SIZE (1024 * 16)
+#define BINARY_IN_TABLE_SIZE (16 * 512)
+#define MAX_FILE_ENTRIES 20
+
+#define MBR_EBR_TYPE 0x05
+#define MBR_MODEM_TYPE 0x06
+#define MBR_MODEM_TYPE2 0x0C
+#define MBR_SBL1_TYPE 0x4D
+#define MBR_SBL2_TYPE 0x51
+#define MBR_SBL3_TYPE 0x45
+#define MBR_RPM_TYPE 0x47
+#define MBR_TZ_TYPE 0x46
+#define MBR_MODEM_ST1_TYPE 0x4A
+#define MBR_MODEM_ST2_TYPE 0x4B
+#define MBR_EFS2_TYPE 0x4E
+
+#define MBR_ABOOT_TYPE 0x4C
+#define MBR_BOOT_TYPE 0x48
+#define MBR_SYSTEM_TYPE 0x82
+#define MBR_USERDATA_TYPE 0x83
+#define MBR_RECOVERY_TYPE 0x60
+#define MBR_MISC_TYPE 0x63
+#define MBR_PROTECTED_TYPE 0xEE
#define GET_LLWORD_FROM_BYTE(x) ((unsigned long long)*(x) | \
((unsigned long long)*(x+1) << 8) | \
@@ -68,16 +109,33 @@
((unsigned long long)*(x+6) << 48) | \
((unsigned long long)*(x+7) << 56))
-struct gpt_entry
+/* Unified mbr and gpt entry types */
+struct partition_entry
{
- unsigned char partition_type_guid[PARTITION_TYPE_GUID_SIZE];
- unsigned char unique_partition_guid[UNIQUE_PARTITION_GUID_SIZE];
- unsigned long long first_lba;
- unsigned long long last_lba;
- unsigned long long attribute_flag;
- unsigned char partition_name[MAX_GPT_NAME_SIZE];
+ unsigned char type_guid[PARTITION_TYPE_GUID_SIZE];
+ unsigned dtype;
+ unsigned char unique_partition_guid[UNIQUE_PARTITION_GUID_SIZE];
+ unsigned long long first_lba;
+ unsigned long long last_lba;
+ unsigned long long size;
+ unsigned long long attribute_flag;
+ unsigned char name[MAX_GPT_NAME_SIZE];
};
-unsigned int mmc_boot_read_gpt(struct mmc_boot_host * mmc_host,
- struct mmc_boot_card * mmc_card);
-unsigned long long gpt_lookup(unsigned char * name, unsigned type);
+static void mbr_fill_name (struct partition_entry *partition_ent, unsigned int type);
+unsigned int mmc_boot_read_gpt( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card);
+unsigned int mmc_boot_read_mbr( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card);
+unsigned partition_get_index (const char * name);
+unsigned long long partition_get_size (int index);
+unsigned long long partition_get_offset (int index);
+unsigned int partition_verify_mbr_signature(unsigned size, unsigned char* buffer);
+unsigned int mbr_partition_get_type(unsigned size, unsigned char* partition,
+ unsigned int *partition_type);
+unsigned int partition_get_type(unsigned size, unsigned char* partition,
+ unsigned int *partition_type);
+unsigned int partition_read_table( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card);
+/* For Debugging */
+void partition_dump(void);
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index 608a3c5..fdd8a9e 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -31,7 +31,7 @@
#include <debug.h>
#include <reg.h>
#include "mmc.h"
-#include "partition_parser.h"
+#include <partition_parser.h>
#include <platform/iomap.h>
#include <platform/timer.h>
@@ -45,13 +45,6 @@
#define MMC_BOOT_DATA_READ 0
#define MMC_BOOT_DATA_WRITE 1
-
-#define MMC_MBR_SIGNATURE_BYTE_0 0x55
-#define MMC_MBR_SIGNATURE_BYTE_1 0xAA
-
-#define PARTITION_TYPE_MBR 0
-#define PARTITION_TYPE_GPT 1
-#define PARTITION_TYPE_GPT_BACKUP 2
static unsigned int mmc_boot_fifo_data_transfer(unsigned int* data_ptr,
@@ -80,10 +73,6 @@
static const unsigned int xfer_rate_value[] =
{ 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 };
-char *ext3_partitions[] = {"system", "userdata", "persist", "cache", "tombstones"};
-char *vfat_partitions[] = {"modem", "mdm", "NONE"};
-unsigned int ext3_count = 0;
-unsigned int vfat_count = 0;
unsigned char mmc_slot = 0;
unsigned int mmc_boot_mci_base = 0;
@@ -97,11 +86,7 @@
struct mmc_boot_host mmc_host;
struct mmc_boot_card mmc_card;
-struct mbr_entry mbr[MAX_PARTITIONS];
-unsigned mmc_partition_count = 0;
-static unsigned gpt_partitions_exist = 0;
-static void mbr_fill_name (struct mbr_entry *mbr_ent, unsigned int type);
static unsigned int mmc_wp(unsigned int addr, unsigned int size,
unsigned char set_clear_wp);
static unsigned int mmc_boot_send_ext_cmd (struct mmc_boot_card* card,
@@ -1496,7 +1481,7 @@
return MMC_BOOT_E_SUCCESS;
}
-
+
/*
* Adjust the interface speed to optimal speed
@@ -2187,195 +2172,6 @@
}
-
-unsigned int mmc_verify_mbr_signature(unsigned size, unsigned char* buffer)
-{
- /* Avoid checking past end of buffer */
- if ((TABLE_SIGNATURE + 1) > size)
- {
- return MMC_BOOT_E_FAILURE;
- }
- /* Check to see if signature exists */
- if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) || \
- (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1))
- {
- dprintf(CRITICAL, "MBR signature does not match. \n" );
- return MMC_BOOT_E_FAILURE;
- }
- return MMC_BOOT_E_SUCCESS;
-}
-
-
-
-void print_mbr_partition_info(struct mbr_entry* mbrEntry)
-{
- char buffer[128];
-
- (void) snprintf(buffer, 128,
- "{name:%s, status:0x%X, type:0x%X, start:0x%X, size:0x%X}\n",
- mbrEntry->name,
- mbrEntry->dstatus,
- mbrEntry->dtype,
- mbrEntry->dfirstsec,
- mbrEntry->dsize
- );
- dprintf(INFO, buffer);
-}
-
-
-
-/* Print the contents of the partition table */
-/* NOTE: exporting this function so that aboot can use it in fastboot
- after display is initialized. */
-void mmc_dump_partition_info()
-{
- if (gpt_partitions_exist)
- {
- /* TODO */
- }
- else
- {
- unsigned int i;
- for (i = 0; i < mmc_partition_count; i++)
- {
- print_mbr_partition_info(&mbr[i]);
- }
- }
-}
-
-
-
-
-/*
- * Read MBR from MMC card and fill partition table.
- */
-static unsigned int mmc_boot_read_mbr(void)
-{
- unsigned char buffer[MMC_BOOT_RD_BLOCK_LEN];
- unsigned int dtype;
- unsigned int dfirstsec;
- unsigned int EBR_first_sec;
- unsigned int EBR_current_sec;
- int ret = MMC_BOOT_E_SUCCESS;
- int idx, i;
-
- dprintf(INFO, "Reading mbr\n");
-
- /* Read the MBR block which is 512 bytes */
- ret = mmc_boot_read_from_card( &mmc_host, &mmc_card, 0, \
- MMC_BOOT_RD_BLOCK_LEN, \
- (unsigned int *)buffer);
- if (ret)
- {
- dprintf(CRITICAL, "Could not read partition from mmc");
- return ret;
- }
-
- ret = mmc_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
- if (ret)
- {
- return ret;
- }
-
- /* Process each of the four partitions in the MBR by reading the table
- information into our mbr table. */
- mmc_partition_count = 0;
- idx = TABLE_ENTRY_0;
- for (i = 0; i < 4; i++)
- {
- dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
- /* Type 0xEE indicates end of MBR and GPT partitions exist */
- if (dtype == MMC_PROTECTED_TYPE)
- {
- gpt_partitions_exist = 1;
- return ret;
- }
- mbr[mmc_partition_count].dtype = dtype;
- mbr[mmc_partition_count].dstatus = \
- buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
- mbr[mmc_partition_count].dfirstsec = \
- GET_LWORD_FROM_BYTE(&buffer[idx + \
- i * TABLE_ENTRY_SIZE + \
- OFFSET_FIRST_SEC]);
- mbr[mmc_partition_count].dsize = \
- GET_LWORD_FROM_BYTE(&buffer[idx + \
- i * TABLE_ENTRY_SIZE + \
- OFFSET_SIZE]);
- dfirstsec = mbr[mmc_partition_count].dfirstsec;
- mbr_fill_name(&mbr[mmc_partition_count], \
- mbr[mmc_partition_count].dtype);
- mmc_partition_count++;
- if (mmc_partition_count == MAX_PARTITIONS)
- return ret;
- }
-
- /* See if the last partition is EBR, if not, parsing is done */
- if (dtype != MMC_EBR_TYPE)
- {
- return ret;
- }
-
- EBR_first_sec = dfirstsec;
- EBR_current_sec = dfirstsec;
-
- dprintf(INFO, "Reading first EBR block from 0x%X\n", EBR_first_sec);
- ret = mmc_boot_read_from_card( &mmc_host, &mmc_card, \
- (EBR_first_sec * 512), \
- MMC_BOOT_RD_BLOCK_LEN, \
- (unsigned int *)buffer);
- if (ret)
- {
- return ret;
- }
- /* Loop to parse the EBR */
- for (i = 0;; i++)
- {
- ret = mmc_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
- if (ret)
- {
- ret = MMC_BOOT_E_SUCCESS;
- break;
- }
- mbr[mmc_partition_count].dstatus = \
- buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
- mbr[mmc_partition_count].dtype = \
- buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
- mbr[mmc_partition_count].dfirstsec = \
- GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
- OFFSET_FIRST_SEC]) + \
- EBR_current_sec;
- mbr[mmc_partition_count].dsize = \
- GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
- OFFSET_SIZE]);
- mbr_fill_name(&(mbr[mmc_partition_count]), \
- mbr[mmc_partition_count].dtype);
- mmc_partition_count++;
- if (mmc_partition_count == MAX_PARTITIONS)
- return ret;
-
- dfirstsec = GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
- if(dfirstsec == 0)
- {
- /* Getting to the end of the EBR tables */
- break;
- }
- /* More EBR to follow - read in the next EBR sector */
- dprintf(INFO, "Reading EBR block from 0x%X\n", EBR_first_sec + dfirstsec);
- ret = mmc_boot_read_from_card( &mmc_host, &mmc_card, \
- ((EBR_first_sec + dfirstsec) * 512), \
- MMC_BOOT_RD_BLOCK_LEN, \
- (unsigned int *)buffer);
- if (ret)
- {
- return ret;
- }
- EBR_current_sec = EBR_first_sec + dfirstsec;
- }
- return ret;
-}
-
-
-
void mmc_display_ext_csd(void)
{
dprintf(SPEW, "part_config: %x\n", ext_csd_buf[179] );
@@ -2430,25 +2226,8 @@
mmc_display_csd();
mmc_display_ext_csd();
- /* Read MBR of the card */
- mmc_ret = mmc_boot_read_mbr();
- if( mmc_ret != MMC_BOOT_E_SUCCESS )
- {
- dprintf(CRITICAL, "MMC Boot: MBR read failed!\n" );
- return MMC_BOOT_E_FAILURE;
- }
-
- /* Read GPT of the card if exist */
- if(gpt_partitions_exist){
- mmc_ret = mmc_boot_read_gpt(&mmc_host, &mmc_card);
- if( mmc_ret != MMC_BOOT_E_SUCCESS )
- {
- dprintf(CRITICAL, "GPT Boot: GPT read failed!\n" );
- return MMC_BOOT_E_FAILURE;
- }
- }
-
- return MMC_BOOT_E_SUCCESS;
+ mmc_ret = partition_read_table(&mmc_host, &mmc_card);
+ return mmc_ret;
}
/*
@@ -2516,13 +2295,13 @@
for (i = 0; i < 4; i++)
{
dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
- if (MMC_EBR_TYPE == dtype)
+ if (MBR_EBR_TYPE == dtype)
{
dprintf(SPEW, "EBR found.\n");
break;
}
}
- if (MMC_EBR_TYPE != dtype)
+ if (MBR_EBR_TYPE != dtype)
{
dprintf(SPEW, "No EBR in this image\n");
goto end;
@@ -2558,16 +2337,8 @@
{
unsigned int ret;
- /* Don't allow overwrite of gpt with a mbr partition */
- if (gpt_partitions_exist)
- {
- ret = MMC_BOOT_E_INVAL;
- dprintf(CRITICAL, "Cannot overwrite GPT partition with MBR image.\n");
- goto end;
- }
-
/* Verify that passed in block is a valid MBR */
- ret = mmc_verify_mbr_signature(size, mbrImage);
+ ret = partition_verify_mbr_signature(size, mbrImage);
if (ret)
{
goto end;
@@ -2581,80 +2352,17 @@
goto end;
}
/* Re-read the MBR partition into mbr table */
- ret = mmc_boot_read_mbr();
+ ret = mmc_boot_read_mbr( &mmc_host, &mmc_card );
if (ret)
{
dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
goto end;
}
- mmc_dump_partition_info();
+ partition_dump();
end:
return ret;
}
-
-
-unsigned int get_mbr_partition_type(unsigned size, unsigned char* partition,
- unsigned int *partition_type)
-{
- unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
-
- if (size < type_offset)
- {
- goto end;
- }
-
- *partition_type = partition[type_offset];
-end:
- return MMC_BOOT_E_SUCCESS;
-}
-
-
-
-unsigned int get_partition_type(unsigned size, unsigned char* partition,
- unsigned int *partition_type)
-{
- unsigned int ret = MMC_BOOT_E_SUCCESS;
-
- /*
- If the block contains the MBR signature, then it's likely either
- MBR or MBR with protective type (GPT). If the MBR signature is
- not there, then it could be the GPT backup.
- */
-
- /* First check the MBR signature */
- ret = mmc_verify_mbr_signature(size, partition);
- if (ret == MMC_BOOT_E_SUCCESS)
- {
- unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
-
- /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
- ret = get_mbr_partition_type(size, partition, &mbr_partition_type);
- if (ret != MMC_BOOT_E_SUCCESS)
- {
- dprintf(CRITICAL, "Cannot get TYPE of partition");
- }
- else if (MMC_PROTECTED_TYPE == mbr_partition_type)
- {
- *partition_type = PARTITION_TYPE_GPT;
- }
- else
- {
- *partition_type = PARTITION_TYPE_MBR;
- }
- }
- else
- {
- /* This could be the GPT backup. Make that assumption for now.
- Anybody who treats the block as GPT backup should check the
- signature. */
- *partition_type = PARTITION_TYPE_GPT_BACKUP;
- }
- return ret;
-}
-
-
-
unsigned int mmc_write_partition(unsigned size, unsigned char* partition)
{
unsigned int ret = MMC_BOOT_E_INVAL;
@@ -2665,7 +2373,7 @@
dprintf(CRITICAL, "NULL partition\n");
goto end;
}
- ret = get_partition_type(size, partition, &partition_type);
+ ret = partition_get_type(size, partition, &partition_type);
if (ret != MMC_BOOT_E_SUCCESS)
{
goto end;
@@ -2708,101 +2416,6 @@
}
/*
- * Fill name for android partition found.
- */
-static void mbr_fill_name (struct mbr_entry *mbr_ent, unsigned int type)
-{
- switch(type)
- {
- memset(mbr_ent->name, 0, 64);
- case MMC_MODEM_TYPE:
- case MMC_MODEM_TYPE2:
- /* if already assigned last name available then return */
- if(!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
- return;
- strcpy((char *)mbr_ent->name,(const char *)vfat_partitions[vfat_count]);
- vfat_count++;
- break;
- case MMC_SBL1_TYPE:
- memcpy(mbr_ent->name,"sbl1",4);
- break;
- case MMC_SBL2_TYPE:
- memcpy(mbr_ent->name,"sbl2",4);
- break;
- case MMC_SBL3_TYPE:
- memcpy(mbr_ent->name,"sbl3",4);
- break;
- case MMC_RPM_TYPE:
- memcpy(mbr_ent->name,"rpm",3);
- break;
- case MMC_TZ_TYPE:
- memcpy(mbr_ent->name,"tz",2);
- break;
- case MMC_ABOOT_TYPE:
- memcpy(mbr_ent->name,"aboot",5);
- break;
- case MMC_BOOT_TYPE:
- memcpy(mbr_ent->name,"boot",4);
- break;
- case MMC_MODEM_ST1_TYPE:
- memcpy(mbr_ent->name,"modem_st1",9);
- break;
- case MMC_MODEM_ST2_TYPE:
- memcpy(mbr_ent->name,"modem_st2",9);
- break;
- case MMC_EFS2_TYPE:
- memcpy(mbr_ent->name,"efs2",4);
- break;
- case MMC_USERDATA_TYPE:
- if (ext3_count == sizeof(ext3_partitions) / sizeof(char*))
- return;
- strcpy((char *)mbr_ent->name,(const char *)ext3_partitions[ext3_count]);
- ext3_count++;
- break;
- case MMC_RECOVERY_TYPE:
- memcpy(mbr_ent->name,"recovery",8);
- break;
- case MMC_MISC_TYPE:
- memcpy(mbr_ent->name,"misc",4);
- break;
- };
-}
-
-/*
- * Returns offset of given partition
- */
-uint64_t mmc_ptn_offset (unsigned char * name)
-{
- unsigned n;
- for(n = 0; n < mmc_partition_count; n++) {
- if(!strcmp((const char *)mbr[n].name, (const char *)name)) {
- return ((uint64_t)mbr[n].dfirstsec * MMC_BOOT_RD_BLOCK_LEN);
- }
- }
- if (gpt_partitions_exist)
- return gpt_lookup(name, PTN_OFFSET);
- else
- return 0;
-}
-
-/*
- * Returns size of given partition
- */
-uint64_t mmc_ptn_size (unsigned char * name)
-{
- unsigned n;
- for(n = 0; n < mmc_partition_count; n++) {
- if(!strcmp((const char *)mbr[n].name, (const char *)name)) {
- return ((uint64_t)mbr[n].dsize * MMC_BOOT_RD_BLOCK_LEN);
- }
- }
- if (gpt_partitions_exist)
- return gpt_lookup(name, PTN_SIZE);
- else
- return 0;
-}
-
-/*
* Function to read registers from MMC or SD card
*/
static unsigned int mmc_boot_read_reg(struct mmc_boot_card *card,
diff --git a/platform/msm_shared/partition_parser.c b/platform/msm_shared/partition_parser.c
index 1f68e4b..23d4778 100644
--- a/platform/msm_shared/partition_parser.c
+++ b/platform/msm_shared/partition_parser.c
@@ -31,32 +31,194 @@
#include "mmc.h"
#include "partition_parser.h"
-static struct gpt_entry gpt[NUM_GPT_PARTITIONS];
-static uint32_t gpt_partition_count = 0;
+char *ext3_partitions[] = {"system", "userdata", "persist", "cache", "tombstones"};
+char *vfat_partitions[] = {"modem", "mdm", "NONE"};
+unsigned int ext3_count = 0;
+unsigned int vfat_count = 0;
+
+struct partition_entry partition_entries[NUM_PARTITIONS];
+unsigned gpt_partitions_exist = 0;
+unsigned partition_count = 0;
+
+//TODO: Remove the dependency of mmc in these functions
+unsigned int partition_read_table( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card)
+{
+ unsigned int ret;
+
+ /* Read MBR of the card */
+ ret = mmc_boot_read_mbr( mmc_host, mmc_card );
+ if( ret != MMC_BOOT_E_SUCCESS )
+ {
+ dprintf(CRITICAL, "MMC Boot: MBR read failed!\n" );
+ return MMC_BOOT_E_FAILURE;
+ }
+
+ /* Read GPT of the card if exist */
+ if(gpt_partitions_exist){
+ ret = mmc_boot_read_gpt(mmc_host, mmc_card);
+ if( ret != MMC_BOOT_E_SUCCESS )
+ {
+ dprintf(CRITICAL, "MMC Boot: GPT read failed!\n" );
+ return MMC_BOOT_E_FAILURE;
+ }
+ }
+ return MMC_BOOT_E_SUCCESS;
+}
+
+/*
+ * Read MBR from MMC card and fill partition table.
+ */
+unsigned int mmc_boot_read_mbr( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card)
+{
+ unsigned char buffer[MMC_BOOT_RD_BLOCK_LEN];
+ unsigned int dtype;
+ unsigned int dfirstsec;
+ unsigned int EBR_first_sec;
+ unsigned int EBR_current_sec;
+ int ret = MMC_BOOT_E_SUCCESS;
+ int idx, i;
+
+ /* Print out the MBR first */
+ ret = mmc_boot_read_from_card( mmc_host, mmc_card, 0, \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)buffer);
+ if (ret)
+ {
+ dprintf(CRITICAL, "Could not read partition from mmc");
+ return ret;
+ }
+
+ /* Check to see if signature exists */
+ ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
+ if (ret)
+ {
+ return ret;
+ }
+
+ /*
+ * Process each of the four partitions in the MBR by reading the table
+ * information into our mbr table.
+ */
+ partition_count = 0;
+ idx = TABLE_ENTRY_0;
+ for (i = 0; i < 4; i++)
+ {
+ /* Type 0xEE indicates end of MBR and GPT partitions exist */
+ dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
+ if (dtype == MBR_PROTECTED_TYPE){
+ gpt_partitions_exist = 1;
+ return ret;
+ }
+ partition_entries[partition_count].dtype = dtype;
+ partition_entries[partition_count].attribute_flag = \
+ buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
+ partition_entries[partition_count].first_lba = \
+ GET_LWORD_FROM_BYTE(&buffer[idx + \
+ i * TABLE_ENTRY_SIZE + \
+ OFFSET_FIRST_SEC]);
+ partition_entries[partition_count].size = \
+ GET_LWORD_FROM_BYTE(&buffer[idx + \
+ i * TABLE_ENTRY_SIZE + \
+ OFFSET_SIZE]);
+ dfirstsec = partition_entries[partition_count].first_lba;
+ mbr_fill_name(&partition_entries[partition_count], \
+ partition_entries[partition_count].dtype);
+ partition_count++;
+ if (partition_count == NUM_PARTITIONS)
+ return ret;
+ }
+
+ /* See if the last partition is EBR, if not, parsing is done */
+ if (dtype != MBR_EBR_TYPE)
+ {
+ return ret;
+ }
+
+ EBR_first_sec = dfirstsec;
+ EBR_current_sec = dfirstsec;
+
+ ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
+ (EBR_first_sec * 512), \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)buffer);
+ if (ret)
+ {
+ return ret;
+ }
+ /* Loop to parse the EBR */
+ for (i = 0;; i++)
+ {
+ ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
+ if (ret)
+ {
+ ret = MMC_BOOT_E_SUCCESS;
+ break;
+ }
+ partition_entries[partition_count].attribute_flag = \
+ buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
+ partition_entries[partition_count].dtype = \
+ buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
+ partition_entries[partition_count].first_lba = \
+ GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
+ OFFSET_FIRST_SEC]) + \
+ EBR_current_sec;
+ partition_entries[partition_count].size = \
+ GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
+ OFFSET_SIZE]);
+ mbr_fill_name(&(partition_entries[partition_count]), \
+ partition_entries[partition_count].dtype);
+ partition_count++;
+ if (partition_count == NUM_PARTITIONS)
+ return ret;
+
+ dfirstsec =
+ GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
+ if(dfirstsec == 0)
+ {
+ /* Getting to the end of the EBR tables */
+ break;
+ }
+ /* More EBR to follow - read in the next EBR sector */
+ dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
+ + dfirstsec);
+ ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
+ ((EBR_first_sec + dfirstsec) * 512), \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)buffer);
+ if (ret)
+ {
+ return ret;
+ }
+ EBR_current_sec = EBR_first_sec + dfirstsec;
+ }
+ return ret;
+}
/*
* Read GPT from MMC and fill partition table
*/
-uint32_t mmc_boot_read_gpt(struct mmc_boot_host * mmc_host,
- struct mmc_boot_card * mmc_card){
+unsigned int mmc_boot_read_gpt( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card)
+{
- int32_t ret = MMC_BOOT_E_SUCCESS;
- uint32_t header_size = 0;
- //uint32_t header_crc = 0;
- uint64_t first_usable_lba = 0;
- uint64_t last_usable_lba = 0;
- uint32_t partition_count = 0;
- uint32_t partition_entry_size = 0;
- //uint32_t partition_array_crc;
- uint8_t data[MMC_BOOT_RD_BLOCK_LEN];
- uint32_t i = 0; /* Counter for each 512 block */
- uint32_t j = 0; /* Counter for each 128 entry in the 512 block */
+ int ret = MMC_BOOT_E_SUCCESS;
+ unsigned int header_size;
+ unsigned long long first_usable_lba;
+ unsigned int max_partition_count;
+ unsigned int partition_entry_size;
+ unsigned char data[MMC_BOOT_RD_BLOCK_LEN];
+ unsigned int i = 0; /* Counter for each 512 block */
+ unsigned int j = 0; /* Counter for each 128 entry in the 512 block */
+ unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
+ unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
/* Print out the GPT first */
- ret = mmc_boot_read_from_card( mmc_host, mmc_card,
- PROTECTIVE_MBR_SIZE,
- MMC_BOOT_RD_BLOCK_LEN,
- (uint32_t *)data);
+ ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
+ PROTECTIVE_MBR_SIZE, \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)data);
/* Check GPT Signature */
if( ((uint32_t *)data)[0] != GPT_SIGNATURE_2 ||
@@ -67,75 +229,260 @@
}
header_size = GET_LWORD_FROM_BYTE(&data[HEADER_SIZE_OFFSET]);
- //header_crc = GET_LWORD_FROM_BYTE(&data[HEADER_CRC_OFFSET]);
first_usable_lba = GET_LLWORD_FROM_BYTE(&data[FIRST_USABLE_LBA_OFFSET]);
- last_usable_lba = GET_LLWORD_FROM_BYTE(&data[LAST_USABLE_LBA_OFFSET]);
- partition_count = GET_LWORD_FROM_BYTE(&data[PARTITION_COUNT_OFFSET]);
+ max_partition_count = GET_LWORD_FROM_BYTE(&data[PARTITION_COUNT_OFFSET]);
partition_entry_size = GET_LWORD_FROM_BYTE(&data[PENTRY_SIZE_OFFSET]);
/* Read GPT Entries */
- for(i = 0; i < (partition_count/4); i++)
+ for(i = 0; i < (max_partition_count/4); i++)
{
ret = mmc_boot_read_from_card( mmc_host, mmc_card,
- PROTECTIVE_MBR_SIZE + PARTITION_TABLE_SIZE +
+ PROTECTIVE_MBR_SIZE +
+ PARTITION_TABLE_SIZE +
(i * MMC_BOOT_RD_BLOCK_LEN),
MMC_BOOT_RD_BLOCK_LEN,
(uint32_t *)data);
if (ret)
{
- dprintf(CRITICAL, "GPT: mmc read card failed reading partition entries.\n" );
+ dprintf(CRITICAL,
+ "GPT: mmc read card failed reading partition entries.\n" );
return ret;
}
for(j=0; j < 4; j++)
{
- memcpy(&(gpt[j+(i*4)].partition_type_guid),
- &data[(j * partition_entry_size)], PARTITION_TYPE_GUID_SIZE);
-
- if (gpt[j+(i*4)].partition_type_guid[0] == 0x00 &&
- gpt[j+(i*4)].partition_type_guid[1] == 0x00)
+ memcpy(&(partition_entries[partition_count].type_guid),
+ &data[(j * partition_entry_size)],
+ PARTITION_TYPE_GUID_SIZE);
+ if (partition_entries[partition_count].type_guid[0] == 0x00 &&
+ partition_entries[partition_count].type_guid[1] == 0x00)
{
- i = partition_count;
+ i = max_partition_count;
break;
}
- gpt_partition_count++;
+ memcpy(&(partition_entries[partition_count].unique_partition_guid),
+ &data[(j * partition_entry_size) +
+ UNIQUE_GUID_OFFSET], UNIQUE_PARTITION_GUID_SIZE);
+ partition_entries[partition_count].first_lba =
+ GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
+ FIRST_LBA_OFFSET]);
+ partition_entries[partition_count].last_lba =
+ GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
+ LAST_LBA_OFFSET]);
+ partition_entries[partition_count].size =
+ partition_entries[partition_count].last_lba -
+ partition_entries[partition_count].first_lba;
+ partition_entries[partition_count].attribute_flag =
+ GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
+ ATTRIBUTE_FLAG_OFFSET]);
- memcpy(&(gpt[j+(i*4)].unique_partition_guid),
- &data[(j * partition_entry_size) + UNIQUE_GUID_OFFSET], UNIQUE_PARTITION_GUID_SIZE);
- gpt[j+(i*4)].first_lba = GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
- FIRST_LBA_OFFSET]);
- gpt[j+(i*4)].last_lba = GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
- LAST_LBA_OFFSET]);
- gpt[j+(i*4)].attribute_flag = GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
- ATTRIBUTE_FLAG_OFFSET]);
- memcpy(&(gpt[j+(i*4)].partition_name),
- &data[(j * partition_entry_size) + PARTITION_NAME_OFFSET], MAX_GPT_NAME_SIZE);
+ memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
+ memcpy(UTF16_name, &data[(j * partition_entry_size) +
+ PARTITION_NAME_OFFSET],
+ MAX_GPT_NAME_SIZE);
+ /*
+ * Currently partition names in *.xml are UTF-8 and lowercase
+ * Only supporting english for now so removing 2nd byte of UTF-16
+ */
+ for(n = 0; n < MAX_GPT_NAME_SIZE/2; n++){
+ partition_entries[partition_count].name[n] = UTF16_name[n*2];
+ }
+ partition_count++;
}
}
+
return ret;
}
-uint64_t gpt_lookup(uint8_t * name, unsigned type){
- uint32_t input_string_length = strlen(name);
- uint8_t UTF16_name[MAX_GPT_NAME_SIZE];
+/*
+ * Fill name for android partition found.
+ */
+static void mbr_fill_name (struct partition_entry *partition_ent,
+ unsigned int type)
+{
+ switch(type)
+ {
+ memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
+ case MBR_MODEM_TYPE:
+ case MBR_MODEM_TYPE2:
+ /* if already assigned last name available then return */
+ if(!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
+ return;
+ strcpy((char *)partition_ent->name,
+ (const char *)vfat_partitions[vfat_count]);
+ vfat_count++;
+ break;
+ case MBR_SBL1_TYPE:
+ memcpy(partition_ent->name,"sbl1",4);
+ break;
+ case MBR_SBL2_TYPE:
+ memcpy(partition_ent->name,"sbl2",4);
+ break;
+ case MBR_SBL3_TYPE:
+ memcpy(partition_ent->name,"sbl3",4);
+ break;
+ case MBR_RPM_TYPE:
+ memcpy(partition_ent->name,"rpm",3);
+ break;
+ case MBR_TZ_TYPE:
+ memcpy(partition_ent->name,"tz",2);
+ break;
+ case MBR_ABOOT_TYPE:
+ memcpy(partition_ent->name,"aboot",5);
+ break;
+ case MBR_BOOT_TYPE:
+ memcpy(partition_ent->name,"boot",4);
+ break;
+ case MBR_MODEM_ST1_TYPE:
+ memcpy(partition_ent->name,"modem_st1",9);
+ break;
+ case MBR_MODEM_ST2_TYPE:
+ memcpy(partition_ent->name,"modem_st2",9);
+ break;
+ case MBR_EFS2_TYPE:
+ memcpy(partition_ent->name,"efs2",4);
+ break;
+ case MBR_USERDATA_TYPE:
+ if (ext3_count == sizeof(ext3_partitions) / sizeof(char*))
+ return;
+ strcpy((char *)partition_ent->name,
+ (const char *)ext3_partitions[ext3_count]);
+ ext3_count++;
+ break;
+ case MBR_RECOVERY_TYPE:
+ memcpy(partition_ent->name,"recovery",8);
+ break;
+ case MBR_MISC_TYPE:
+ memcpy(partition_ent->name,"misc",4);
+ break;
+ };
+}
+
+/*
+ * Find index of parition in array of partition entries
+ */
+unsigned partition_get_index (const char * name)
+{
+ unsigned int input_string_length = strlen(name);
unsigned n;
- memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
- /* Currently partition names in partition.xml are UTF-8 and lowercase */
- for(n = 0; n < input_string_length && n < MAX_GPT_NAME_SIZE/2; n++){
- UTF16_name[n*2] = name[n];
- UTF16_name[n*2+1] = 0x00;
- }
- for(n = 0; n < gpt_partition_count; n++){
- if(!memcmp(&UTF16_name, &gpt[n].partition_name, MAX_GPT_NAME_SIZE)){
- if(type == PTN_SIZE)
- return ((uint64_t)(gpt[n].last_lba - gpt[n].first_lba) * MMC_BOOT_RD_BLOCK_LEN);
- else if(type == PTN_OFFSET)
- return ((uint64_t)gpt[n].first_lba * MMC_BOOT_RD_BLOCK_LEN);
- else
- return 0;
+ for(n = 0; n < partition_count; n++){
+ if(!memcmp(name, &partition_entries[n].name, input_string_length) &&
+ input_string_length == strlen((const char *)&partition_entries[n].name))
+ {
+ return n;
}
}
- return 0;
+ return INVALID_PTN;
+}
+
+/* Get size of the partition */
+unsigned long long partition_get_size (int index)
+{
+ if (index == INVALID_PTN)
+ return 0;
+ else{
+ return partition_entries[index].size * MMC_BOOT_RD_BLOCK_LEN;
+ }
+}
+
+/* Get offset of the partition */
+unsigned long long partition_get_offset (int index)
+{
+ if (index == INVALID_PTN)
+ return 0;
+ else{
+ return partition_entries[index].first_lba * MMC_BOOT_RD_BLOCK_LEN;
+ }
+}
+
+/* Debug: Print all parsed partitions */
+void partition_dump()
+{
+ unsigned i = 0;
+ for (i=0; i< partition_count; i++){
+ dprintf(SPEW,
+ "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
+ i, partition_entries[i].name, partition_entries[i].size,
+ partition_entries[i].dtype, partition_entries[i].first_lba,
+ partition_entries[i].last_lba);
+ }
+}
+
+unsigned int partition_verify_mbr_signature(unsigned size,
+ unsigned char* buffer)
+{
+ /* Avoid checking past end of buffer */
+ if ((TABLE_SIGNATURE + 1) > size)
+ {
+ return MMC_BOOT_E_FAILURE;
+ }
+ /* Check to see if signature exists */
+ if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) || \
+ (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1))
+ {
+ dprintf(CRITICAL, "MBR signature does not match. \n" );
+ return MMC_BOOT_E_FAILURE;
+ }
+ return MMC_BOOT_E_SUCCESS;
+}
+
+unsigned int mbr_partition_get_type(unsigned size, unsigned char* partition,
+ unsigned int *partition_type)
+{
+ unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
+
+ if (size < type_offset)
+ {
+ goto end;
+ }
+
+ *partition_type = partition[type_offset];
+end:
+ return MMC_BOOT_E_SUCCESS;
+}
+
+unsigned int partition_get_type(unsigned size, unsigned char* partition,
+ unsigned int *partition_type)
+{
+ unsigned int ret = MMC_BOOT_E_SUCCESS;
+
+ /*
+ * If the block contains the MBR signature, then it's likely either
+ * MBR or MBR with protective type (GPT). If the MBR signature is
+ * not there, then it could be the GPT backup.
+ */
+
+ /* First check the MBR signature */
+ ret = partition_verify_mbr_signature(size, partition);
+ if (ret == MMC_BOOT_E_SUCCESS)
+ {
+ unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
+
+ /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
+ ret = mbr_partition_get_type(size, partition, &mbr_partition_type);
+ if (ret != MMC_BOOT_E_SUCCESS)
+ {
+ dprintf(CRITICAL, "Cannot get TYPE of partition");
+ }
+ else if (MBR_PROTECTED_TYPE == mbr_partition_type)
+ {
+ *partition_type = PARTITION_TYPE_GPT;
+ }
+ else
+ {
+ *partition_type = PARTITION_TYPE_MBR;
+ }
+ }
+ else
+ {
+ /*
+ * This could be the GPT backup. Make that assumption for now.
+ * Anybody who treats the block as GPT backup should check the
+ * signature.
+ */
+ *partition_type = PARTITION_TYPE_GPT_BACKUP;
+ }
+ return ret;
}
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index a170109..abe15d7 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -41,7 +41,9 @@
$(LOCAL_DIR)/i2c_qup.o \
$(LOCAL_DIR)/uart_dm.o \
$(LOCAL_DIR)/qgic.o \
- $(LOCAL_DIR)/mdp4.o
+ $(LOCAL_DIR)/mdp4.o \
+ $(LOCAL_DIR)/crypto4_eng.o \
+ $(LOCAL_DIR)/crypto_hash.o
endif
ifeq ($(PLATFORM),msm7x27a)
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index d3469d6..6d1a616 100644
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -190,6 +190,7 @@
HW_PLATFORM_FLUID = 3,
HW_PLATFORM_SVLTE = 4,
HW_PLATFORM_QT = 6,
+ HW_PLATFORM_LIQUID = 9,
HW_PLATFORM_DRAGON = 10,
HW_PLATFORM_32BITS = 0x7FFFFFFF
};
diff --git a/platform/omap3/debug.c b/platform/omap3/debug.c
index ac6300d..87aac8d 100644
--- a/platform/omap3/debug.c
+++ b/platform/omap3/debug.c
@@ -37,7 +37,7 @@
uart_putc(DEBUG_UART, c);
}
-int dgetc(char *c)
+int dgetc(char *c, bool wait)
{
int _c;
@@ -79,8 +79,3 @@
PANIC_UNIMPLEMENTED;
}
-uint32_t debug_cycle_count(void)
-{
-// PANIC_UNIMPLEMENTED;
- return 0;
-}
diff --git a/platform/omap5912/debug.c b/platform/omap5912/debug.c
index d190fa0..3afb39c 100644
--- a/platform/omap5912/debug.c
+++ b/platform/omap5912/debug.c
@@ -25,9 +25,14 @@
#include <debug.h>
#include <printf.h>
#include <kernel/thread.h>
+#include <kernel/timer.h>
#include <platform/debug.h>
#include <arch/ops.h>
#include <platform/omap5912.h>
+#include <lib/cbuf.h>
+
+static cbuf_t debug_buf;
+static timer_t debug_timer;
static void write_uart_reg(int uart, int reg, unsigned char data)
{
@@ -94,15 +99,24 @@
uart_putc(0, c);
}
-int dgetc(char *c)
+static enum handler_return debug_timer_callback(timer_t *t, time_t now, void *arg)
{
- int _c;
+ signed char c;
+ c = uart_getc(0, false);
+ if (c > 0) {
+ cbuf_write(&debug_buf, &c, 1, false);
+ return INT_RESCHEDULE;
+ } else {
+ return INT_NO_RESCHEDULE;
+ }
+}
- if ((_c = uart_getc(0, false)) < 0)
- return -1;
+int dgetc(char *c, bool wait)
+{
+ ssize_t len;
- *c = _c;
- return 0;
+ len = cbuf_read(&debug_buf, c, 1, wait);
+ return len;
}
void debug_dump_regs(void)
@@ -136,8 +150,8 @@
PANIC_UNIMPLEMENTED;
}
-uint32_t debug_cycle_count(void)
+void platform_init_debug(void)
{
-// PANIC_UNIMPLEMENTED;
- return 0;
+ cbuf_initialize(&debug_buf, 512);
+ timer_set_periodic(&debug_timer, 10, &debug_timer_callback, NULL);
}
diff --git a/platform/omap5912/platform.c b/platform/omap5912/platform.c
index 1dd703d..a4dfbbc 100644
--- a/platform/omap5912/platform.c
+++ b/platform/omap5912/platform.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -48,5 +48,6 @@
void platform_init(void)
{
+ platform_init_debug();
}
diff --git a/platform/omap5912/platform_p.h b/platform/omap5912/platform_p.h
index 872ea2b..c3c3349 100644
--- a/platform/omap5912/platform_p.h
+++ b/platform/omap5912/platform_p.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008 Travis Geiselbrecht
+ * Copyright (c) 2008-2009 Travis Geiselbrecht
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -25,6 +25,7 @@
void platform_init_interrupts(void);
void platform_init_timer(void);
+void platform_init_debug(void);
#endif
diff --git a/platform/omap5912/rules.mk b/platform/omap5912/rules.mk
index e1bddc1..2ab8cbe 100644
--- a/platform/omap5912/rules.mk
+++ b/platform/omap5912/rules.mk
@@ -4,6 +4,9 @@
ARM_CPU := arm926ej-s
CPU := generic
+MODULES += \
+ lib/cbuf
+
INCLUDES += \
-I$(LOCAL_DIR)/include
diff --git a/platform/pc/console.c b/platform/pc/console.c
new file mode 100644
index 0000000..3537539
--- /dev/null
+++ b/platform/pc/console.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <arch/x86.h>
+#include <platform/pc.h>
+#include <platform/console.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+/* CGA values */
+#define CURSOR_START 0x0A
+#define CURSOR_END 0x0B
+#define VIDEO_ADDRESS_MSB 0x0C
+#define VIDEO_ADDRESS_LSB 0x0D
+#define CURSOR_POS_MSB 0x0E
+#define CURSOR_POS_LSB 0x0F
+
+/* curr settings */
+static unsigned char curr_x;
+static unsigned char curr_y;
+static unsigned char curr_start;
+static unsigned char curr_end;
+static unsigned char curr_attr;
+
+/* video page buffer */
+#define VPAGE_SIZE 2048
+#define PAGE_MAX 8
+
+static int active_page = 0;
+static int visual_page = 0;
+
+static int curs_x[PAGE_MAX];
+static int curs_y[PAGE_MAX];
+
+static struct {
+ int x1, y1, x2, y2;
+} view_window = {
+ 0, 0, 79, 24
+};
+
+void platform_init_console(void)
+{
+ curr_save();
+ window(0, 0, 79, 24);
+ clear();
+ place(0, 0);
+}
+
+void set_visual_page(int page)
+{
+ unsigned short page_offset = page*VPAGE_SIZE;
+ visual_page = page;
+
+ outp(CGA_INDEX_REG, VIDEO_ADDRESS_LSB);
+ outp(CGA_DATA_REG, page_offset & 0xFF);
+ outp(CGA_INDEX_REG, VIDEO_ADDRESS_MSB);
+ outp(CGA_DATA_REG, (page_offset >> 8) & 0xFF);
+}
+
+void set_active_page(int page)
+{
+ curs_x[active_page] = curr_x;
+ curs_y[active_page] = curr_y;
+ curr_x = curs_x[page];
+ curr_y = curs_y[page];
+ active_page = page;
+}
+
+int get_visual_page(void)
+{
+ return visual_page;
+}
+
+int get_active_page(void)
+{
+ return active_page;
+}
+
+void place(int x,int y)
+{
+ unsigned short cursor_word = x + y*80 + active_page*VPAGE_SIZE;
+
+ /*
+ * program CGA using index reg, then data reg
+ */
+ outp(CGA_INDEX_REG, CURSOR_POS_LSB);
+ outp(CGA_DATA_REG, cursor_word & 0xFF);
+ outp(CGA_INDEX_REG, CURSOR_POS_MSB);
+ outp(CGA_DATA_REG, (cursor_word >> 8) & 0xFF);
+
+ curr_x = x;
+ curr_y = y;
+}
+
+void cursor(int start,int end)
+{
+ outp(CGA_INDEX_REG, CURSOR_START);
+ outp(CGA_DATA_REG, start);
+ outp(CGA_INDEX_REG, CURSOR_END);
+ outp(CGA_DATA_REG, end);
+}
+
+void curr_save(void)
+{
+ /* grab some info from the bios data area (these should be defined in memmap.h */
+ curr_attr = *((unsigned char *)0xB8000 + 159);
+ curr_x = *((unsigned char *)0x00450);
+ curr_y = *((unsigned char *)0x00451);
+ curr_end = *((unsigned char *)0x00460);
+ curr_start = *((unsigned char *)0x00461);
+ active_page = visual_page = 0;
+}
+
+void curr_restore(void)
+{
+ *((unsigned char *)0x00450) = curr_x;
+ *((unsigned char *)0x00451) = curr_y;
+
+ place(curr_x, curr_y);
+ cursor(curr_start, curr_end);
+}
+
+void window(int x1, int y1, int x2, int y2) {
+ view_window.x1 = x1;
+ view_window.y1 = y1;
+ view_window.x2 = x2;
+ view_window.y2 = y2;
+
+ //place(x1, y1);
+}
+
+void _clear(char c,char attr,int x1,int y1,int x2,int y2)
+{
+ register int i,j;
+ unsigned short w = attr;
+
+ w <<= 8; w |= c;
+ for (i = x1; i <= x2; i++) {
+ for (j = y1; j <= y2; j++) {
+ *((unsigned short *)(0xB8000 + 2*i+160*j + 2*active_page*VPAGE_SIZE)) = w;
+ }
+ }
+
+ place(x1,y1);
+ curr_y = y1;
+ curr_x = x1;
+}
+
+void clear()
+{
+ _clear(' ', curr_attr, view_window.x1, view_window.y1, view_window.x2,
+ view_window.y2);
+}
+
+void _scroll(char attr, int x1, int y1, int x2, int y2)
+{
+ register int x,y;
+ unsigned short xattr = attr << 8,w;
+ unsigned char *v = (unsigned char *)(0xB8000 + active_page*(2*VPAGE_SIZE));
+
+ for (y = y1+1; y <= y2; y++) {
+ for (x = x1; x <= x2; x++) {
+ w = *((unsigned short *) (v + 2*(y*80+x)));
+ *((unsigned short *)(v + 2*((y-1)*80+x))) = w;
+ }
+ }
+
+ for (x = x1; x <= x2; x++) {
+ *((unsigned short *)(v + 2*((y-1)*80+x))) = xattr;
+ }
+}
+
+void scroll(void)
+{
+ _scroll(curr_attr, view_window.x1, view_window.y1, view_window.x2,
+ view_window.y2);
+}
+
+void cputc(char c)
+{
+ static unsigned short scan_x, x, y;
+ unsigned char *v = (unsigned char *)(0xB8000 + active_page*(2*VPAGE_SIZE));
+ x = curr_x;
+ y = curr_y;
+
+ switch (c) {
+ case '\t':
+ x += 8;
+ if (x >= view_window.x2+1) {
+ x = view_window.x1;
+ if (y == view_window.y2) {
+ scroll();
+ } else {
+ y++;
+ }
+ } else {
+ scan_x = 0;
+
+ while ((scan_x+8) < x) {
+ scan_x += 8;
+ }
+
+ x = scan_x;
+ }
+ break;
+
+ case '\n':
+ x = view_window.x1;
+ if (y == view_window.y2) {
+ scroll();
+ } else {
+ y++;
+ }
+ break;
+
+ case '\b':
+ x--;
+ *(v + 2*(x + y*80)) = ' ';
+ break;
+
+ default:
+ *(v + 2*(x + y*80)) = c;
+ x++;
+
+ if (x >= view_window.x2+1) {
+ x = view_window.x1;
+ if (y == view_window.y2) {
+ scroll();
+ } else {
+ y++;
+ }
+ }
+ }
+
+ place(x, y);
+}
+
+void cputs(char *s)
+{
+ char c;
+ while (*s != '\0') {
+ c = *s++;
+ cputc(c);
+ }
+}
+
+void puts_xy(int x,int y,char attr,char *s)
+{
+ unsigned char *v = (unsigned char *)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE));
+ while (*s != 0) {
+ *v = *s; s++; v++;
+ *v = attr; v++;
+ }
+}
+
+void putc_xy(int x, int y, char attr, char c)
+{
+ unsigned char *v = (unsigned char *)(0xB8000 + (80*y+x)*2 + active_page*(2*VPAGE_SIZE));
+ *v = c; v++;
+ *v = attr;
+}
+
+int printf_xy(int x, int y, char attr, char *fmt, ...)
+{
+ char cbuf[200];
+ va_list parms;
+ int result;
+
+ va_start(parms, fmt);
+ result = vsprintf(cbuf, fmt, parms);
+ va_end(parms);
+
+ puts_xy(x, y, attr, cbuf);
+
+ return result;
+}
diff --git a/platform/pc/debug.c b/platform/pc/debug.c
new file mode 100644
index 0000000..b1d70ee
--- /dev/null
+++ b/platform/pc/debug.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdarg.h>
+#include <reg.h>
+#include <printf.h>
+#include <kernel/thread.h>
+#include <arch/x86.h>
+#include <platform/pc/memmap.h>
+#include <platform/console.h>
+#include <platform/keyboard.h>
+#include <platform/debug.h>
+
+void _dputc(char c)
+{
+ cputc(c);
+}
+
+int dgetc(char *c, bool wait)
+{
+ int ret = platform_read_key(c);
+ //if (ret < 0)
+ // arch_idle();
+
+ return ret;
+}
+
+void debug_dump_regs(void)
+{
+}
+
+void platform_halt(void)
+{
+ for(;;) {
+ x86_cli();
+ x86_hlt();
+ }
+}
+
+void debug_dump_memory_bytes(void *mem, int len)
+{
+}
+
+void debug_dump_memory_halfwords(void *mem, int len)
+{
+}
+
+void debug_dump_memory_words(void *mem, int len)
+{
+}
+
+void debug_set_trace_level(int trace_type, int level)
+{
+}
+
diff --git a/platform/pc/include/platform/console.h b/platform/pc/include/platform/console.h
new file mode 100644
index 0000000..3a1b802
--- /dev/null
+++ b/platform/pc/include/platform/console.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_CONSOLE_H
+#define __PLATFORM_CONSOLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void platform_init_console(void);
+
+void set_visual_page(int page);
+void set_active_page(int page);
+
+int get_visual_page(void);
+int get_active_page(void);
+
+void place(int x,int y);
+void cursor(int start, int end);
+
+void _clear(char c, char attr, int x1, int y1, int x2, int y2);
+void clear(void);
+
+void _scroll(char attr, int x1, int y1, int x2, int y2);
+void scroll(void);
+
+void curr_save(void);
+void curr_restore(void);
+
+void cputc(char c);
+void cputs(char *s);
+
+void window(int x1, int y1, int x2, int y2);
+
+void putc_xy(int x, int y, char attr, char c);
+void puts_xy(int x, int y, char attr, char *s);
+
+int printf_xy(int x, int y, char attr, char *fmt, ...) __PRINTFLIKE(4, 5);
+
+#define CURSOR_BLOCK() cursor(0, 15);
+#define CURSOR_OFF() cursor(16, 16);
+#define CURSOR_STD() cursor(14, 15);
+
+/* text colors */
+#define BLACK 0
+#define BLUE 1
+#define GREEN 2
+#define CYAN 3
+#define RED 4
+#define MAGENTA 5
+#define BROWN 6
+#define LIGHTGRAY 7
+#define DARKGRAY 8
+#define LIGHTBLUE 9
+#define LIGHTGREEN 10
+#define LIGHTCYAN 11
+#define LIGHTRED 12
+#define LIGHTMAGENTA 13
+#define YELLOW 14
+#define WHITE 15
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/platform/pc/include/platform/keyboard.h b/platform/pc/include/platform/keyboard.h
new file mode 100644
index 0000000..5464995
--- /dev/null
+++ b/platform/pc/include/platform/keyboard.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_KEYBOARD_H
+#define __PLATFORM_KEYBOARD_H
+
+void platform_init_keyboard(void);
+
+int platform_read_key(char *c);
+
+#endif
diff --git a/platform/pc/include/platform/multiboot.h b/platform/pc/include/platform/multiboot.h
new file mode 100644
index 0000000..f5d3310
--- /dev/null
+++ b/platform/pc/include/platform/multiboot.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_MULTIBOOT_H
+#define __PLATFORM_MULTIBOOT_H
+
+#include <sys/types.h>
+
+/* magic number for multiboot header */
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+
+/* flags for multiboot header */
+#ifdef __ELF__
+#define MULTIBOOT_HEADER_FLAGS 0x00000003
+#else
+#define MULTIBOOT_HEADER_FLAGS 0x00010003
+#endif
+
+/* magic number passed by multiboot-compliant boot loaders */
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+#ifndef ASSEMBLY
+
+/* multiboot header */
+typedef struct multiboot_header
+{
+ uint32_t magic;
+ uint32_t flags;
+ uint32_t checksum;
+ uint32_t header_addr;
+ uint32_t load_addr;
+ uint32_t load_end_addr;
+ uint32_t bss_end_addr;
+ uint32_t entry_addr;
+} multiboot_header_t;
+
+/* symbol table for a.out */
+typedef struct aout_symbol_table
+{
+ uint32_t tabsize;
+ uint32_t strsize;
+ uint32_t addr;
+ uint32_t reserved;
+} aout_symbol_table_t;
+
+/* section header table for ELF */
+typedef struct elf_section_header_table
+{
+ uint32_t num;
+ uint32_t size;
+ uint32_t addr;
+ uint32_t shndx;
+} elf_section_header_table_t;
+
+/* multiboot info */
+typedef struct multiboot_info
+{
+ uint32_t flags;
+ uint32_t mem_lower;
+ uint32_t mem_upper;
+ uint32_t boot_device;
+ uint32_t cmdline;
+ uint32_t mods_count;
+ uint32_t mods_addr;
+ union
+ {
+ aout_symbol_table_t aout_sym;
+ elf_section_header_table_t elf_sec;
+ } u;
+ uint32_t mmap_length;
+ uint32_t mmap_addr;
+} multiboot_info_t;
+
+enum {
+ MB_INFO_MEM_SIZE = 0x001,
+ MB_INFO_BOOT_DEV = 0x002,
+ MB_INFO_CMD_LINE = 0x004,
+ MB_INFO_MODS = 0x008,
+ MB_INFO_SYMS = 0x010,
+ MB_INFO_MMAP = 0x020,
+ MB_INFO_DRIVES = 0x040,
+ MB_INFO_CONFIG = 0x080,
+ MB_INFO_BOOT_LOADER = 0x100,
+ MB_INFO_APM_TABLE = 0x200,
+ MB_INFO_VBE = 0x400,
+};
+
+/* module structure */
+typedef struct module
+{
+ uint32_t mod_start;
+ uint32_t mod_end;
+ uint32_t string;
+ uint32_t reserved;
+} module_t;
+
+/* memory map - be careful that the offset 0 is base_addr_low without size */
+typedef struct memory_map
+{
+ uint32_t size;
+ uint32_t base_addr_low;
+ uint32_t base_addr_high;
+ uint32_t length_low;
+ uint32_t length_high;
+ uint32_t type;
+} memory_map_t;
+
+/* memory map entry types */
+enum {
+ MB_MMAP_TYPE_AVAILABLE = 0x01,
+ MB_MMAP_TYPE_RESERVED = 0x02,
+ MB_MMAP_TYPE_ACPI_RECLAIM = 0x03,
+ MB_MMAP_TYPE_ACPI_NVS = 0x04,
+};
+
+#endif
+
+#endif
diff --git a/platform/pc/include/platform/pc.h b/platform/pc/include/platform/pc.h
new file mode 100644
index 0000000..a8a7251
--- /dev/null
+++ b/platform/pc/include/platform/pc.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_PC_H
+#define __PLATFORM_PC_H
+
+#include <platform/pc/memmap.h>
+#include <platform/pc/iomap.h>
+
+/* NOTE: keep arch/x86/crt0.S in sync with these definitions */
+
+/* interrupts */
+#define INT_VECTORS 0x31
+
+/* defined interrupts */
+#define INT_BASE 0x20
+#define INT_PIT 0x20
+#define INT_KEYBOARD 0x21
+#define INT_PIC2 0x22
+
+#define INT_BASE2 0x28
+#define INT_CMOSRTC 0x28
+#define INT_PS2MOUSE 0x2c
+#define INT_IDE0 0x2e
+#define INT_IDE1 0x2f
+
+/* exceptions */
+#define INT_DIVIDE_0 0x00
+#define INT_DEBUG_EX 0x01
+#define INT_INVALID_OP 0x06
+#define INT_DEV_NA_EX 0x07
+
+/* faults */
+#define INT_STACK_FAULT 0x0c
+#define INT_GP_FAULT 0x0d
+#define INT_PAGE_FAULT 0x0e
+
+/* APIC vectors */
+#define INT_APIC_TIMER 0x22
+
+#define INT_SYSCALL 0x30
+
+/* PIC remap bases */
+#define PIC1_BASE 0x20
+#define PIC2_BASE 0x28
+
+#endif
+
diff --git a/platform/pc/include/platform/pc/iomap.h b/platform/pc/include/platform/pc/iomap.h
new file mode 100644
index 0000000..fe75964
--- /dev/null
+++ b/platform/pc/include/platform/pc/iomap.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __IOMAP_H
+#define __IOMAP_H
+
+/* i8253/i8254 programmable interval timer registers */
+#define I8253_CONTROL_REG 0x43
+#define I8253_DATA_REG 0x40
+
+/* i8042 keyboard controller registers */
+#define I8042_COMMAND_REG 0x64
+#define I8042_STATUS_REG 0x64
+#define I8042_DATA_REG 0x60
+
+/* CGA registers */
+#define CGA_INDEX_REG 0x3D4
+#define CGA_DATA_REG 0x3D5
+
+#endif
diff --git a/platform/pc/include/platform/pc/memmap.h b/platform/pc/include/platform/pc/memmap.h
new file mode 100644
index 0000000..1243aad
--- /dev/null
+++ b/platform/pc/include/platform/pc/memmap.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __MEMMAP_H
+#define __MEMMAP_H
+
+/* some helpful macros */
+#define REG(x) ((volatile unsigned int *)(x))
+#define REG_H(x) ((volatile unsigned short *)(x))
+#define REG_B(x) ((volatile unsigned char *)(x))
+
+/* TODO: put fixed memory address definitions here */
+
+#endif
diff --git a/platform/pc/interrupts.c b/platform/pc/interrupts.c
new file mode 100644
index 0000000..c507c19
--- /dev/null
+++ b/platform/pc/interrupts.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <debug.h>
+#include <err.h>
+#include <reg.h>
+#include <kernel/thread.h>
+#include <platform/interrupts.h>
+#include <arch/ops.h>
+#include <arch/x86.h>
+#include "platform_p.h"
+#include <platform/pc.h>
+
+void x86_gpf_handler(struct x86_iframe *frame);
+void x86_invop_handler(struct x86_iframe *frame);
+void x86_unhandled_exception(struct x86_iframe *frame);
+
+#define PIC1 0x20
+#define PIC2 0xA0
+
+#define ICW1 0x11
+#define ICW4 0x01
+
+struct int_handler_struct {
+ int_handler handler;
+ void *arg;
+};
+
+static struct int_handler_struct int_handler_table[INT_VECTORS];
+
+/*
+ * Cached IRQ mask (enabled/disabled)
+ */
+static uint8_t irqMask[2];
+
+/*
+ * init the PICs and remap them
+ */
+static void map(uint32_t pic1, uint32_t pic2)
+{
+ /* send ICW1 */
+ outp(PIC1, ICW1);
+ outp(PIC2, ICW1);
+
+ /* send ICW2 */
+ outp(PIC1 + 1, pic1); /* remap */
+ outp(PIC2 + 1, pic2); /* pics */
+
+ /* send ICW3 */
+ outp(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
+ outp(PIC2 + 1, 2);
+
+ /* send ICW4 */
+ outp(PIC1 + 1, 5);
+ outp(PIC2 + 1, 1);
+
+ /* disable all IRQs */
+ outp(PIC1 + 1, 0xff);
+ outp(PIC2 + 1, 0xff);
+
+ irqMask[0] = 0xff;
+ irqMask[1] = 0xff;
+}
+
+static void enable(unsigned int vector, bool enable)
+{
+ if (vector >= PIC1_BASE && vector < PIC1_BASE + 8) {
+ vector -= PIC1_BASE;
+
+ uint8_t bit = 1 << vector;
+
+ if (enable && (irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] &= ~bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ } else if (!enable && !(irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] |= bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ }
+ } else if (vector >= PIC2_BASE && vector < PIC2_BASE + 8) {
+ vector -= PIC2_BASE;
+
+ uint8_t bit = 1 << vector;
+
+ if (enable && (irqMask[1] & bit)) {
+ irqMask[1] = inp(PIC2 + 1);
+ irqMask[1] &= ~bit;
+ outp(PIC2 + 1, irqMask[1]);
+ irqMask[1] = inp(PIC2 + 1);
+ } else if (!enable && !(irqMask[1] & bit)) {
+ irqMask[1] = inp(PIC2 + 1);
+ irqMask[1] |= bit;
+ outp(PIC2 + 1, irqMask[1]);
+ irqMask[1] = inp(PIC2 + 1);
+ }
+
+ bit = 1 << (INT_PIC2 - PIC1_BASE);
+
+ if (irqMask[1] != 0xff && (irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] &= ~bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ } else if (irqMask[1] == 0 && !(irqMask[0] & bit)) {
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[0] |= bit;
+ outp(PIC1 + 1, irqMask[0]);
+ irqMask[0] = inp(PIC1 + 1);
+ }
+ } else {
+ //dprintf(DEBUG, "Invalid PIC interrupt: %02x\n", vector);
+ }
+}
+
+void issueEOI(unsigned int vector)
+{
+ if (vector >= PIC1_BASE && vector <= PIC1_BASE + 7) {
+ outp(PIC1, 0x20);
+ } else if (vector >= PIC2_BASE && vector <= PIC2_BASE + 7) {
+ outp(PIC2, 0x20);
+ outp(PIC1, 0x20); // must issue both for the second PIC
+ }
+}
+
+void platform_init_interrupts(void)
+{
+ // rebase the PIC out of the way of processor exceptions
+ map(PIC1_BASE, PIC2_BASE);
+}
+
+status_t mask_interrupt(unsigned int vector)
+{
+ if (vector >= INT_VECTORS)
+ return ERR_INVALID_ARGS;
+
+// dprintf(DEBUG, "%s: vector %d\n", __PRETTY_FUNCTION__, vector);
+
+ enter_critical_section();
+
+ enable(vector, false);
+
+ exit_critical_section();
+
+ return NO_ERROR;
+}
+
+
+void platform_mask_irqs(void)
+{
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[1] = inp(PIC2 + 1);
+
+ outp(PIC1 + 1, 0xff);
+ outp(PIC2 + 1, 0xff);
+
+ irqMask[0] = inp(PIC1 + 1);
+ irqMask[1] = inp(PIC2 + 1);
+}
+
+status_t unmask_interrupt(unsigned int vector)
+{
+ if (vector >= INT_VECTORS)
+ return ERR_INVALID_ARGS;
+
+// dprintf("%s: vector %d\n", __PRETTY_FUNCTION__, vector);
+
+ enter_critical_section();
+
+ enable(vector, true);
+
+ exit_critical_section();
+
+ return NO_ERROR;
+}
+
+enum handler_return platform_irq(struct x86_iframe *frame)
+{
+ // get the current vector
+ unsigned int vector = frame->vector;
+
+#if THREAD_STATS
+ thread_stats.interrupts++;
+#endif
+
+ // deliver the interrupt
+ enum handler_return ret = INT_NO_RESCHEDULE;
+
+ switch (vector) {
+ case INT_GP_FAULT:
+ x86_gpf_handler(frame);
+ break;
+
+ case INT_INVALID_OP:
+ x86_invop_handler(frame);
+ break;
+
+ case INT_DIVIDE_0:
+ case INT_DEBUG_EX:
+ case INT_DEV_NA_EX:
+ case INT_PAGE_FAULT:
+ case INT_STACK_FAULT:
+ case 3:
+ x86_unhandled_exception(frame);
+ break;
+
+ default:
+ if (int_handler_table[vector].handler)
+ ret = int_handler_table[vector].handler(int_handler_table[vector].arg);
+ }
+
+ // ack the interrupt
+ issueEOI(vector);
+
+ return ret;
+}
+
+void register_int_handler(unsigned int vector, int_handler handler, void *arg)
+{
+ if (vector >= INT_VECTORS)
+ panic("register_int_handler: vector out of range %d\n", vector);
+
+ enter_critical_section();
+
+ int_handler_table[vector].arg = arg;
+ int_handler_table[vector].handler = handler;
+
+ exit_critical_section();
+}
+
+
diff --git a/platform/pc/keyboard.c b/platform/pc/keyboard.c
new file mode 100644
index 0000000..27e3d3c
--- /dev/null
+++ b/platform/pc/keyboard.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <err.h>
+#include <reg.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/console.h>
+#include <platform/timer.h>
+#include <platform/pc.h>
+#include "platform_p.h"
+#include <arch/x86.h>
+#include <lib/cbuf.h>
+
+static inline int i8042_read_data(void)
+{
+ return inp(I8042_DATA_REG);
+}
+
+static inline int i8042_read_status(void)
+{
+ return inp(I8042_STATUS_REG);
+}
+
+static inline void i8042_write_data(int val)
+{
+ outp(I8042_DATA_REG, val);
+}
+
+static inline void i8042_write_command(int val)
+{
+ outp(I8042_COMMAND_REG, val);
+}
+
+/*
+ * timeout in milliseconds
+ */
+#define I8042_CTL_TIMEOUT 500
+
+/*
+ * status register bits
+ */
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_MUXERR 0x04
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+/*
+ * control register bits
+ */
+#define I8042_CTR_KBDINT 0x01
+#define I8042_CTR_AUXINT 0x02
+#define I8042_CTR_IGNKEYLK 0x08
+#define I8042_CTR_KBDDIS 0x10
+#define I8042_CTR_AUXDIS 0x20
+#define I8042_CTR_XLATE 0x40
+
+/*
+ * commands
+ */
+#define I8042_CMD_CTL_RCTR 0x0120
+#define I8042_CMD_CTL_WCTR 0x1060
+#define I8042_CMD_CTL_TEST 0x01aa
+
+#define I8042_CMD_KBD_DIS 0x00ad
+#define I8042_CMD_KBD_EN 0x00ae
+#define I8042_CMD_KBD_TEST 0x01ab
+#define I8042_CMD_KBD_MODE 0x01f0
+
+/*
+ * used for flushing buffers. the i8042 internal buffer shoudn't exceed this.
+ */
+#define I8042_BUFFER_LENGTH 32
+
+static inline void delay(time_t delay) {
+ bigtime_t start = current_time();
+
+ while (start + delay > current_time());
+}
+
+/* scancodes we want to do something with that don't translate via table */
+#define SCANCODE_LSHIFT 0x2a
+#define SCANCODE_RSHIFT 0x36
+
+/* scancode translation tables */
+static const int KeyCodeSingleLower[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=','\b','\t', // 0
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']','\n', -1, 'a', 's', // 1
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';','\'', '`', -1,'\\', 'z', 'x', 'c', 'v', // 2
+ 'b', 'n', 'm', ',', '.', '/', -1, '*', -1, ' ', -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+static const int KeyCodeMultiLower[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+static const int KeyCodeSingleUpper[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+','\b','\t', // 0
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}','\n', -1, 'A', 'S', // 1
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~', -1, '|', 'Z', 'X', 'C', 'V', // 2
+ 'B', 'N', 'M', '<', '>', '?', -1, '*', -1, ' ', -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+static const int KeyCodeMultiUpper[] = {
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 3
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7
+};
+
+/*
+ * state key flags
+ */
+static bool key_lshift;
+static bool key_rshift;
+
+static cbuf_t key_buf;
+
+static void i8042_process_scode(uint8_t scode, unsigned int flags)
+{
+ static int lastCode = 0;
+ int keyCode;
+ uint8_t keyUpBit;
+
+ bool multi = lastCode == 0xe0;
+
+ // save the key up event bit
+ keyUpBit = scode & 0x80;
+ scode &= 0x7f;
+
+ if (scode == SCANCODE_LSHIFT) {
+ key_lshift = !keyUpBit;
+ }
+
+ if (scode == SCANCODE_RSHIFT) {
+ key_rshift = !keyUpBit;
+ }
+
+ if (key_lshift || key_rshift) {
+ keyCode = multi ? KeyCodeMultiUpper[scode] : KeyCodeSingleUpper[scode];
+ } else {
+ keyCode = multi ? KeyCodeMultiLower[scode] : KeyCodeSingleLower[scode];
+ }
+
+ /*printf_xy(71, 3, BLUE, "%02x%02x %c %c%c", multi ? lastCode : 0, scode,
+ keyCode != -1 ? (char) keyCode : ' ', key_lshift ? 'L' : ' ',
+ key_rshift ? 'R' : ' ');*/
+
+ if (keyCode != -1 && !keyUpBit) {
+ char c = (char) keyCode;
+ cbuf_write(&key_buf, &c, 1, false);
+ }
+
+ // update the last received code
+ lastCode = scode;
+}
+
+static int i8042_wait_read(void)
+{
+ int i = 0;
+ while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
+ delay(1);
+ i++;
+ }
+ return -(i == I8042_CTL_TIMEOUT);
+}
+
+static int i8042_wait_write(void)
+{
+ int i = 0;
+ while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
+ delay(1);
+ i++;
+ }
+ return -(i == I8042_CTL_TIMEOUT);
+}
+
+static int i8042_flush(void)
+{
+ unsigned char data;
+ int i = 0;
+
+ //enter_critical_section();
+
+ while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_LENGTH)) {
+ delay(1);
+ data = i8042_read_data();
+ }
+
+ //exit_critical_section();
+
+ return i;
+}
+
+static int i8042_command(uint8_t *param, int command)
+{
+ int retval = 0, i = 0;
+
+ //enter_critical_section();
+
+ retval = i8042_wait_write();
+ if (!retval) {
+ i8042_write_command(command & 0xff);
+ }
+
+ if (!retval) {
+ for (i = 0; i < ((command >> 12) & 0xf); i++) {
+ if ((retval = i8042_wait_write())) {
+ break;
+ }
+
+ i8042_write_data(param[i]);
+ }
+ }
+
+ if (!retval) {
+ for (i = 0; i < ((command & 0xf0) >> 8); i++) {
+ if ((retval = i8042_wait_read())) {
+ break;
+ }
+
+ if (i8042_read_status() & I8042_STR_AUXDATA) {
+ param[i] = ~i8042_read_data();
+ } else {
+ param[i] = i8042_read_data();
+ }
+ }
+ }
+
+ //exit_critical_section();
+
+ return retval;
+}
+
+static enum handler_return i8042_interrupt(void *arg)
+{
+ uint8_t str, data = 0;
+
+ //enter_critical_section();
+ str = i8042_read_status();
+ if (str & I8042_STR_OBF) {
+ data = i8042_read_data();
+ }
+ //exit_critical_section();
+
+ if (str & I8042_STR_OBF) {
+ i8042_process_scode(data,
+ ((str & I8042_STR_PARITY) ? I8042_STR_PARITY : 0) |
+ ((str & I8042_STR_TIMEOUT) ? I8042_STR_TIMEOUT : 0));
+ }
+
+ return INT_NO_RESCHEDULE;
+}
+
+int platform_read_key(char *c)
+{
+ ssize_t len;
+
+ len = cbuf_read(&key_buf, c, 1, true);
+ return len;
+}
+
+void platform_init_keyboard(void)
+{
+ uint8_t ctr;
+
+ cbuf_initialize(&key_buf, 32);
+
+ i8042_flush();
+
+ if (i8042_command(&ctr, I8042_CMD_CTL_RCTR)) {
+ dprintf(DEBUG, "Failed to read CTR while initializing i8042\n");
+ return;
+ }
+
+ // turn on translation
+ ctr |= I8042_CTR_XLATE;
+
+ // enable keyboard and keyboard irq
+ ctr &= ~I8042_CTR_KBDDIS;
+ ctr |= I8042_CTR_KBDINT;
+
+ if (i8042_command(&ctr, I8042_CMD_CTL_WCTR)) {
+ dprintf(DEBUG, "Failed to write CTR while initializing i8042\n");
+ return;
+ }
+
+ register_int_handler(INT_KEYBOARD, &i8042_interrupt, NULL);
+ unmask_interrupt(INT_KEYBOARD);
+
+ i8042_interrupt(NULL);
+}
diff --git a/platform/pc/pci.c b/platform/pc/pci.c
new file mode 100644
index 0000000..c1c255f
--- /dev/null
+++ b/platform/pc/pci.c
@@ -0,0 +1,576 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <arch/x86/descriptor.h>
+#include <dev/pci.h>
+
+static int last_bus = 0;
+
+typedef struct {
+ uint16_t size;
+ void *offset;
+ uint16_t selector;
+} __PACKED irq_routing_options_t;
+
+static int pci_type1_detect(void);
+static int pci_bios_detect(void);
+
+int pci_get_last_bus(void)
+{
+ return last_bus;
+}
+
+/*
+ * pointers to installed PCI routines
+ */
+int (*g_pci_find_pci_device)(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index);
+int (*g_pci_find_pci_class_code)(pci_location_t *state, uint32_t class_code, uint16_t index);
+
+int (*g_pci_read_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t *value);
+int (*g_pci_read_config_half)(const pci_location_t *state, uint32_t reg, uint16_t *value);
+int (*g_pci_read_config_word)(const pci_location_t *state, uint32_t reg, uint32_t *value);
+
+int (*g_pci_write_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t value);
+int (*g_pci_write_config_half)(const pci_location_t *state, uint32_t reg, uint16_t value);
+int (*g_pci_write_config_word)(const pci_location_t *state, uint32_t reg, uint32_t value);
+
+int (*g_pci_get_irq_routing_options)(irq_routing_options_t *options, uint16_t *pci_irqs);
+int (*g_pci_set_irq_hw_int)(const pci_location_t *state, uint8_t int_pin, uint8_t irq);
+
+
+int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
+{
+ enter_critical_section();
+
+ int res = g_pci_find_pci_device(state, device_id, vendor_id, index);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
+{
+ enter_critical_section();
+
+ int res = g_pci_find_pci_class_code(state, class_code, index);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
+{
+ enter_critical_section();
+
+ int res = g_pci_read_config_byte(state, reg, value);
+
+ exit_critical_section();
+
+ return res;
+}
+int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
+{
+ enter_critical_section();
+
+ int res = g_pci_read_config_half(state, reg, value);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
+{
+ enter_critical_section();
+
+ int res = g_pci_read_config_word(state, reg, value);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
+{
+ enter_critical_section();
+
+ int res = g_pci_write_config_byte(state, reg, value);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
+{
+ enter_critical_section();
+
+ int res = g_pci_write_config_half(state, reg, value);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
+{
+ enter_critical_section();
+
+ int res = g_pci_write_config_word(state, reg, value);
+
+ exit_critical_section();
+
+ return res;
+}
+
+
+int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs)
+{
+ enter_critical_section();
+
+ irq_routing_options_t options;
+ options.size = sizeof(irq_routing_entry) * *count;
+ options.selector = DATA_SELECTOR;
+ options.offset = entries;
+
+ int res = g_pci_get_irq_routing_options(&options, pci_irqs);
+
+ *count = options.size / sizeof(irq_routing_entry);
+
+ exit_critical_section();
+
+ return res;
+}
+
+int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
+{
+ enter_critical_section();
+
+ int res = g_pci_set_irq_hw_int(state, int_pin, irq);
+
+ exit_critical_section();
+
+ return res;
+}
+
+void pci_init(void)
+{
+ if (!pci_bios_detect()) {
+ dprintf(INFO, "pci bios functions installed\n");
+ dprintf(INFO, "last pci bus is %d\n", last_bus);
+ }
+}
+
+#define PCIBIOS_PRESENT 0xB101
+#define PCIBIOS_FIND_PCI_DEVICE 0xB102
+#define PCIBIOS_FIND_PCI_CLASS_CODE 0xB103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xB106
+#define PCIBIOS_READ_CONFIG_BYTE 0xB108
+#define PCIBIOS_READ_CONFIG_WORD 0xB109
+#define PCIBIOS_READ_CONFIG_DWORD 0xB10A
+#define PCIBIOS_WRITE_CONFIG_BYTE 0xB10B
+#define PCIBIOS_WRITE_CONFIG_WORD 0xB10C
+#define PCIBIOS_WRITE_CONFIG_DWORD 0xB10D
+#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0xB10E
+#define PCIBIOS_PCI_SET_IRQ_HW_INT 0xB10F
+
+#define PCIBIOS_SUCCESSFUL 0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
+#define PCIBIOS_BAD_VENDOR_ID 0x83
+#define PCIBIOS_DEVICE_NOT_FOUND 0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
+#define PCIBIOS_SET_FAILED 0x88
+#define PCIBIOS_BUFFER_TOO_SMALL 0x89
+
+/*
+ * far call structure used by BIOS32 routines
+ */
+static struct {
+ uint32_t offset;
+ uint16_t selector;
+} __PACKED bios32_entry;
+
+/*
+ * BIOS32 entry header
+ */
+typedef struct {
+ uint8_t magic[4]; // "_32_"
+ void * entry; // entry point
+ uint8_t revision;
+ uint8_t length;
+ uint8_t checksum;
+ uint8_t reserved[5];
+} __PACKED pci_bios_info;
+
+/*
+ * scan for pci bios
+ */
+static const char * pci_bios_magic = "_32_";
+static pci_bios_info *find_pci_bios_info(void) {
+ uint32_t *head = (uint32_t *) 0x000e0000;
+ int8_t sum, *b;
+ uint i;
+
+ while (head < (uint32_t *) 0x000ffff0) {
+ if (*head == *(uint32_t *) pci_bios_magic) {
+ // perform the checksum
+ sum = 0;
+ b = (int8_t *) head;
+ for (i=0; i < sizeof(pci_bios_info); i++) {
+ sum += b[i];
+ }
+
+ if (sum == 0) {
+ return (pci_bios_info *) head;
+ }
+ }
+
+ head += 4;
+ }
+
+ return NULL;
+}
+
+/*
+ * local BIOS32 PCI routines
+ */
+static int bios_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
+{
+ uint32_t bx, ret;
+
+ __asm__(
+ "lcall *(%%edi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=b"(bx),
+ "=a"(ret)
+ : "1"(PCIBIOS_FIND_PCI_DEVICE),
+ "c"(device_id),
+ "d"(vendor_id),
+ "S"(index),
+ "D"(&bios32_entry));
+
+ state->bus = bx >> 8;
+ state->dev_fn = bx & 0xFF;
+
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
+{
+ uint32_t bx, ret;
+
+ __asm__(
+ "lcall *(%%edi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=b"(bx),
+ "=a"(ret)
+ : "1"(PCIBIOS_FIND_PCI_CLASS_CODE),
+ "c"(class_code),
+ "S"(index),
+ "D"(&bios32_entry));
+
+ state->bus = bx >> 8;
+ state->dev_fn = bx & 0xFF;
+
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+
+static int bios_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=c"(*value),
+ "=a"(ret)
+ : "1"(PCIBIOS_READ_CONFIG_BYTE),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=c"(*value),
+ "=a"(ret)
+ : "1"(PCIBIOS_READ_CONFIG_WORD),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=c"(*value),
+ "=a"(ret)
+ : "1"(PCIBIOS_READ_CONFIG_DWORD),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_WRITE_CONFIG_BYTE),
+ "c"(value),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_WRITE_CONFIG_WORD),
+ "c"(value),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
+{
+ uint32_t bx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_WRITE_CONFIG_DWORD),
+ "c"(value),
+ "b"(bx),
+ "D"(reg),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static int bios_get_irq_routing_options(irq_routing_options_t *route_buffer, uint16_t *pciIrqs)
+{
+ uint32_t ret;
+
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=b"(*pciIrqs),
+ "=a"(ret)
+ : "1"(PCIBIOS_GET_IRQ_ROUTING_OPTIONS),
+ "b"(0),
+ "D"(route_buffer),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xff;
+}
+
+static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
+{
+ uint32_t bx, cx, ret;
+
+ bx = state->bus;
+ bx <<= 8;
+ bx |= state->dev_fn;
+ cx = irq;
+ cx <<= 8;
+ cx |= int_pin;
+ __asm__(
+ "lcall *(%%esi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(ret)
+ : "0"(PCIBIOS_PCI_SET_IRQ_HW_INT),
+ "b"(bx),
+ "c"(cx),
+ "S"(&bios32_entry));
+ ret >>= 8;
+ return ret & 0xFF;
+}
+
+static const char *pci_signature = "PCI ";
+static int pci_bios_detect(void) {
+ pci_bios_info * pci = find_pci_bios_info();
+
+ if (pci != NULL) {
+ /*printf("Found PCI structure at %08x\n", (uint32_t) pci);
+
+ printf("\nPCI header info:\n");
+ printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2],
+ pci->magic[3]);
+ printf("%08x\n", (uint32_t) pci->entry);
+ printf("%d\n", pci->length * 16);
+ printf("%d\n", pci->checksum);*/
+
+ uint32_t adr, temp, len;
+ uint8_t err;
+
+ bios32_entry.offset = (uint32_t) pci->entry;
+ bios32_entry.selector = CODE_SELECTOR;
+
+ __asm__(
+ "lcall *(%%edi)"
+ : "=a"(err), /* AL out=status */
+ "=b"(adr), /* EBX out=code segment base adr */
+ "=c"(len), /* ECX out=code segment size */
+ "=d"(temp) /* EDX out=entry pt offset in code */
+ : "0"(0x49435024),/* EAX in=service="$PCI" */
+ "1"(0), /* EBX in=0=get service entry pt */
+ "D"(&bios32_entry)
+ );
+
+ if (err == 0x80) {
+ dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
+ return -1;
+ }
+
+ if (err != 0) {
+ dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
+ return -1;
+ }
+
+ bios32_entry.offset = adr + temp;
+
+ // now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
+ uint16_t present, version, busses;
+ uint32_t signature;
+ __asm__(
+ "lcall *(%%edi) \n\t"
+ "jc 1f \n\t"
+ "xor %%ah,%%ah \n"
+ "1:"
+ : "=a"(present),
+ "=b"(version),
+ "=c"(busses),
+ "=d"(signature)
+ : "0"(PCIBIOS_PRESENT),
+ "D"(&bios32_entry)
+ );
+
+ if (present & 0xff00) {
+ dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8);
+ return -1;
+ }
+
+ if (signature != *(uint32_t *)pci_signature) {
+ dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature);
+ return -1;
+ }
+
+ //dprintf(DEBUG, "busses=%04x\n", busses);
+ last_bus = busses & 0xff;
+
+ g_pci_find_pci_device = bios_find_pci_device;
+ g_pci_find_pci_class_code = bios_find_pci_class_code;
+
+ g_pci_read_config_word = bios_read_config_word;
+ g_pci_read_config_half = bios_read_config_half;
+ g_pci_read_config_byte = bios_read_config_byte;
+
+ g_pci_write_config_word = bios_write_config_word;
+ g_pci_write_config_half = bios_write_config_half;
+ g_pci_write_config_byte = bios_write_config_byte;
+
+ g_pci_get_irq_routing_options = bios_get_irq_routing_options;
+ g_pci_set_irq_hw_int = bios_set_irq_hw_int;
+
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/platform/pc/platform.c b/platform/pc/platform.c
new file mode 100644
index 0000000..ca5a946
--- /dev/null
+++ b/platform/pc/platform.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <err.h>
+#include <debug.h>
+#include <arch/x86/mmu.h>
+#include <platform.h>
+#include "platform_p.h"
+#include <platform/pc.h>
+#include <platform/multiboot.h>
+#include <platform/console.h>
+#include <platform/keyboard.h>
+#include <dev/pci.h>
+
+extern multiboot_info_t *_multiboot_info;
+extern unsigned int _heap_end;
+
+void platform_init_mmu_mappings(void)
+{
+ /* do some memory map initialization */
+}
+
+
+void platform_init_multiboot_info(void)
+{
+ unsigned int i;
+
+ if (_multiboot_info) {
+ if (_multiboot_info->flags & MB_INFO_MEM_SIZE) {
+ _heap_end = _multiboot_info->mem_upper * 1024;
+ }
+
+ if (_multiboot_info->flags & MB_INFO_MMAP) {
+ memory_map_t *mmap = (memory_map_t *) (_multiboot_info->mmap_addr - 4);
+
+ dprintf(DEBUG, "mmap length: %u\n", _multiboot_info->mmap_length);
+
+ for (i=0; i < _multiboot_info->mmap_length / sizeof(memory_map_t); i++) {
+ dprintf(DEBUG, "base=%08x, length=%08x, type=%02x\n",
+ mmap[i].base_addr_low, mmap[i].length_low, mmap[i].type);
+
+ if (mmap[i].type == MB_MMAP_TYPE_AVAILABLE && mmap[i].base_addr_low >= _heap_end) {
+ _heap_end = mmap[i].base_addr_low + mmap[i].length_low;
+ } else if (mmap[i].type != MB_MMAP_TYPE_AVAILABLE && mmap[i].base_addr_low >= _heap_end) {
+ /*
+ * break on first memory hole above default heap end for now.
+ * later we can add facilities for adding free chunks to the
+ * heap for each segregated memory region.
+ */
+ break;
+ }
+ }
+ }
+ }
+}
+
+void platform_early_init(void)
+{
+ /* update the heap end so we can take advantage of more ram */
+ platform_init_multiboot_info();
+
+ /* get the text console working */
+ platform_init_console();
+
+ /* initialize the interrupt controller */
+ platform_init_interrupts();
+
+ /* initialize the timer */
+ platform_init_timer();
+}
+
+void platform_init(void)
+{
+ platform_init_keyboard();
+
+ pci_init();
+}
+
diff --git a/platform/pc/platform_p.h b/platform/pc/platform_p.h
new file mode 100644
index 0000000..b8c2d95
--- /dev/null
+++ b/platform/pc/platform_p.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __PLATFORM_P_H
+#define __PLATFORM_P_H
+
+void platform_init_interrupts(void);
+void platform_init_timer(void);
+
+#endif
+
diff --git a/platform/pc/rules.mk b/platform/pc/rules.mk
new file mode 100644
index 0000000..e10fb1b
--- /dev/null
+++ b/platform/pc/rules.mk
@@ -0,0 +1,23 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+ARCH := x86
+CPU := generic
+
+MODULES += \
+ lib/cbuf
+
+INCLUDES += \
+ -I$(LOCAL_DIR)/include
+
+OBJS += \
+ $(LOCAL_DIR)/interrupts.o \
+ $(LOCAL_DIR)/platform.o \
+ $(LOCAL_DIR)/timer.o \
+ $(LOCAL_DIR)/debug.o \
+ $(LOCAL_DIR)/console.o \
+ $(LOCAL_DIR)/keyboard.o \
+ $(LOCAL_DIR)/pci.o
+
+LINKER_SCRIPT += \
+ $(BUILDDIR)/kernel.ld
+
diff --git a/platform/pc/timer.c b/platform/pc/timer.c
new file mode 100644
index 0000000..2211511
--- /dev/null
+++ b/platform/pc/timer.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <sys/types.h>
+#include <err.h>
+#include <reg.h>
+#include <debug.h>
+#include <kernel/thread.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/console.h>
+#include <platform/timer.h>
+#include <platform/pc.h>
+#include "platform_p.h"
+#include <arch/x86.h>
+
+static platform_timer_callback t_callback;
+static void *callback_arg;
+
+static uint64_t next_trigger_time;
+static uint64_t next_trigger_delta;
+
+static uint64_t timer_delta_time;
+static uint64_t timer_current_time;
+
+static uint16_t divisor;
+
+#define INTERNAL_FREQ 1193182ULL
+#define INTERNAL_FREQ_3X 3579546ULL
+
+status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, time_t interval)
+{
+ enter_critical_section();
+
+ t_callback = callback;
+ callback_arg = arg;
+
+ next_trigger_delta = (uint64_t) interval << 32;
+ next_trigger_time = timer_current_time + next_trigger_delta;
+
+ exit_critical_section();
+
+ return NO_ERROR;
+}
+
+time_t current_time(void)
+{
+ time_t time;
+
+ enter_critical_section();
+ time = (time_t) (timer_current_time >> 32);
+ exit_critical_section();
+
+ return time;
+}
+
+bigtime_t current_time_hires(void)
+{
+ bigtime_t time;
+
+ enter_critical_section();
+ time = (bigtime_t) ((timer_current_time >> 22) * 1000) >> 10;
+ exit_critical_section();
+
+ return time;
+}
+static enum handler_return os_timer_tick(void *arg)
+{
+ uint64_t delta;
+
+ timer_current_time += timer_delta_time;
+
+ time_t time = current_time();
+ //bigtime_t btime = current_time_hires();
+ //printf_xy(71, 0, WHITE, "%08u", (uint32_t) time);
+ //printf_xy(63, 1, WHITE, "%016llu", (uint64_t) btime);
+
+ if (t_callback && timer_current_time >= next_trigger_time) {
+ delta = timer_current_time - next_trigger_time;
+ next_trigger_time = timer_current_time + next_trigger_delta - delta;
+
+ return t_callback(callback_arg, time);
+ } else {
+ return INT_NO_RESCHEDULE;
+ }
+}
+
+static void set_pit_frequency(uint32_t frequency)
+{
+ uint32_t count, remainder;
+
+ /* figure out the correct divisor for the desired frequency */
+ if (frequency <= 18) {
+ count = 0xffff;
+ } else if (frequency >= INTERNAL_FREQ) {
+ count = 1;
+ } else {
+ count = INTERNAL_FREQ_3X / frequency;
+ remainder = INTERNAL_FREQ_3X % frequency;
+
+ if (remainder >= INTERNAL_FREQ_3X / 2) {
+ count += 1;
+ }
+
+ count /= 3;
+ remainder = count % 3;
+
+ if (remainder >= 1) {
+ count += 1;
+ }
+ }
+
+ divisor = count & 0xffff;
+
+ /*
+ * funky math that i don't feel like explaining. essentially 32.32 fixed
+ * point representation of the configured timer delta.
+ */
+ timer_delta_time = (3685982306ULL * count) >> 10;
+
+ //dprintf(DEBUG, "set_pit_frequency: dt=%016llx\n", timer_delta_time);
+ //dprintf(DEBUG, "set_pit_frequency: divisor=%04x\n", divisor);
+
+ /*
+ * setup the Programmable Interval Timer
+ * timer 0, mode 2, binary counter, LSB followed by MSB
+ */
+ outp(I8253_CONTROL_REG, 0x34);
+ outp(I8253_DATA_REG, divisor & 0xff); // LSB
+ outp(I8253_DATA_REG, divisor >> 8); // MSB
+}
+
+void platform_init_timer(void)
+{
+ timer_current_time = 0;
+
+ set_pit_frequency(1000); // ~1ms granularity
+
+ register_int_handler(INT_PIT, &os_timer_tick, NULL);
+ unmask_interrupt(INT_PIT);
+}
+
+void platform_halt_timers(void)
+{
+ mask_interrupt(INT_PIT);
+}
+
diff --git a/project/armemu-test.mk b/project/armemu-test.mk
index 151beed..9b222e6 100644
--- a/project/armemu-test.mk
+++ b/project/armemu-test.mk
@@ -4,6 +4,15 @@
TARGET := armemu
MODULES += \
+ lib/bio \
+ lib/partition \
+ lib/bcache \
+ lib/fs \
+ lib/fs/ext2 \
+ lib/gfx \
+ lib/gfxconsole \
+ lib/text \
+ lib/tga \
app/tests \
app/shell
diff --git a/project/pc-x86-test.mk b/project/pc-x86-test.mk
new file mode 100644
index 0000000..d0b1937
--- /dev/null
+++ b/project/pc-x86-test.mk
@@ -0,0 +1,17 @@
+# top level project rules for the pc-x86-test project
+#
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+TARGET := pc-x86
+MODULES += \
+ app/tests \
+ app/shell \
+ app/pcitests
+
+# extra rules to copy the pc-x86.conf file to the build dir
+#$(BUILDDIR)/pc-x86.conf: $(LOCAL_DIR)/pc-x86.conf
+# @echo copy $< to $@
+# $(NOECHO)cp $< $@
+
+#EXTRA_BUILDDEPS += $(BUILDDIR)/pc-x86.conf
+#GENERATED += $(BUILDDIR)/pc-x86.conf
diff --git a/scripts/buildall b/scripts/buildall
index 5601d7c..906ee0c 100755
--- a/scripts/buildall
+++ b/scripts/buildall
@@ -1,7 +1,14 @@
#!/bin/sh
PROJECTS="armemu-test sam7ex256-test osk5912-test qemu-arm-test beagle-test surf-test"
+FAILED=""
for p in $PROJECTS; do
- PROJECT=$p make -j2
+ PROJECT=$p make -j2 || FAILED="$FAILED $p"
done
+
+if [ "$FAILED" != "" ]; then
+ echo
+ echo some projects have failed to build:
+ echo $FAILED
+fi
diff --git a/scripts/do-armemu-test b/scripts/do-armemu-test
index 1d910f6..04c9e50 100755
--- a/scripts/do-armemu-test
+++ b/scripts/do-armemu-test
@@ -2,6 +2,10 @@
export PROJECT=armemu-test
-make -C ../armemu &&
-make &&
+if [ ! -f blk.bin ]; then
+ dd if=/dev/zero of=blk.bin bs=1024k count=16
+fi
+
+make -j8 -C ../armemu &&
+make -j8 &&
(cd build-$PROJECT; ../../armemu/build-generic/armemu)
diff --git a/scripts/do-sam7ex256-test b/scripts/do-sam7ex256-test
index 4505ad6..d549831 100755
--- a/scripts/do-sam7ex256-test
+++ b/scripts/do-sam7ex256-test
@@ -1,6 +1,6 @@
#!/bin/sh
-export DEBUG=true
+export DEBUG=2
export PROJECT=sam7ex256-test
make
diff --git a/target/armemu/armemu.conf b/target/armemu/armemu.conf
new file mode 100644
index 0000000..bcd1bff
--- /dev/null
+++ b/target/armemu/armemu.conf
@@ -0,0 +1,23 @@
+[cpu]
+core = arm926ejs
+
+# the rom file is loaded at address 0x0
+[rom]
+file = lk.bin
+
+[system]
+display = yes
+console = yes
+network = no
+block = yes
+
+[network]
+device = /dev/tap0
+
+[block]
+file = ../blk.bin
+
+[display]
+width = 800
+height = 600
+depth = 32
diff --git a/target/armemu/rules.mk b/target/armemu/rules.mk
index d79834a..4c7bdd1 100644
--- a/target/armemu/rules.mk
+++ b/target/armemu/rules.mk
@@ -4,3 +4,8 @@
PLATFORM := armemu
+$(BUILDDIR)/armemu.conf: $(LOCAL_DIR)/armemu.conf
+ cp $< $@
+
+EXTRA_BUILDDEPS += $(BUILDDIR)/armemu.conf
+GENERATED += $(BUILDDIR)/armemu.conf
diff --git a/target/msm8960/init.c b/target/msm8960/init.c
index e8dba0a..48482e1 100644
--- a/target/msm8960/init.c
+++ b/target/msm8960/init.c
@@ -49,6 +49,7 @@
#define LINUX_MACHTYPE_8960_MTP 3397
#define LINUX_MACHTYPE_8960_FLUID 3398
#define LINUX_MACHTYPE_8960_APQ 3399
+#define LINUX_MACHTYPE_8960_LIQUID 3535
extern void dmb(void);
@@ -151,6 +152,9 @@
case HW_PLATFORM_FLUID:
mach_id = LINUX_MACHTYPE_8960_FLUID;
break;
+ case HW_PLATFORM_LIQUID:
+ mach_id = LINUX_MACHTYPE_8960_LIQUID;
+ break;
default:
mach_id = LINUX_MACHTYPE_8960_CDP;
};
diff --git a/target/pc-x86/rules.mk b/target/pc-x86/rules.mk
new file mode 100644
index 0000000..ed7bbfb
--- /dev/null
+++ b/target/pc-x86/rules.mk
@@ -0,0 +1,5 @@
+# mostly null target configuration for pc-x86
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+PLATFORM := pc
+