added Rick_1995 code in

This commit is contained in:
cmhtcleo 2011-11-06 23:17:49 +00:00
parent a57a973d36
commit 9a76f8e4e9
113 changed files with 18917 additions and 13631 deletions

File diff suppressed because it is too large Load Diff

View File

@ -33,10 +33,20 @@
#include <kernel/event.h>
#include <dev/udc.h>
void boot_linux(void *bootimg, unsigned sz);
/*
unsigned int c_usb_stat=0;
unsigned int fastboot_cstat(void){
return c_usb_stat;
}
void fastboot_sstat(unsigned int stat){
c_usb_stat = stat;
}
*/
/* todo: give lk strtoul and nuke this */
static unsigned hex2unsigned(const char *x)
unsigned hex2unsigned(const char *x)
{
unsigned n = 0;
@ -76,7 +86,7 @@ struct fastboot_var {
const char *value;
};
static struct fastboot_cmd *cmdlist;
struct fastboot_cmd *cmdlist;
void fastboot_register(const char *prefix,
void (*handle)(const char *arg, void *data, unsigned sz))
@ -92,7 +102,7 @@ void fastboot_register(const char *prefix,
}
}
static struct fastboot_var *varlist;
struct fastboot_var *varlist;
void fastboot_publish(const char *name, const char *value)
{
@ -107,32 +117,32 @@ void fastboot_publish(const char *name, const char *value)
}
static event_t usb_online;
static event_t txn_done;
static unsigned char buffer[4096];
static struct udc_endpoint *in, *out;
static struct udc_request *req;
event_t usb_online;
event_t txn_done;
unsigned char buffer[4096];
struct udc_endpoint *in, *out;
struct udc_request *req;
int txn_status;
static void *download_base;
static unsigned download_max;
static unsigned download_size;
void *download_base;
unsigned download_max;
unsigned download_size;
#define STATE_OFFLINE 0
#define STATE_COMMAND 1
#define STATE_COMPLETE 2
#define STATE_ERROR 3
static unsigned fastboot_state = STATE_OFFLINE;
unsigned fastboot_state = STATE_OFFLINE;
static void req_complete(struct udc_request *req, unsigned actual, int status)
void req_complete(struct udc_request *req, unsigned actual, int status)
{
txn_status = status;
req->length = actual;
event_signal(&txn_done, 0);
}
static int usb_read(void *_buf, unsigned len)
int usb_read(void *_buf, unsigned len)
{
int r;
unsigned xfer;
@ -149,13 +159,13 @@ static int usb_read(void *_buf, unsigned len)
req->complete = req_complete;
r = udc_request_queue(out, req);
if (r < 0) {
dprintf(INFO, "usb_read() queue failed\n");
//dprintf(INFO, "usb_read() queue failed\n");
goto oops;
}
event_wait(&txn_done);
if (txn_status < 0) {
dprintf(INFO, "usb_read() transaction failed\n");
//dprintf(INFO, "usb_read() transaction failed\n");
goto oops;
}
@ -170,11 +180,12 @@ static int usb_read(void *_buf, unsigned len)
return count;
oops:
//fastboot_sstat(0);
fastboot_state = STATE_ERROR;
return -1;
}
static int usb_write(void *buf, unsigned len)
int usb_write(void *buf, unsigned len)
{
int r;
@ -186,17 +197,18 @@ static int usb_write(void *buf, unsigned len)
req->complete = req_complete;
r = udc_request_queue(in, req);
if (r < 0) {
dprintf(INFO, "usb_write() queue failed\n");
//dprintf(INFO, "usb_write() queue failed\n");
goto oops;
}
event_wait(&txn_done);
if (txn_status < 0) {
dprintf(INFO, "usb_write() transaction failed\n");
//dprintf(INFO, "usb_write() transaction failed\n");
goto oops;
}
return req->length;
oops:
//fastboot_sstat(0);
fastboot_state = STATE_ERROR;
return -1;
}
@ -233,7 +245,7 @@ int fastboot_write(void *buf, unsigned len)
return usb_write(buf, len);
}
static void cmd_getvar(const char *arg, void *data, unsigned sz)
void cmd_getvar(const char *arg, void *data, unsigned sz)
{
struct fastboot_var *var;
@ -246,7 +258,7 @@ static void cmd_getvar(const char *arg, void *data, unsigned sz)
fastboot_okay("");
}
static void cmd_download(const char *arg, void *data, unsigned sz)
void cmd_download(const char *arg, void *data, unsigned sz)
{
char response[64];
unsigned len = hex2unsigned(arg);
@ -263,7 +275,7 @@ static void cmd_download(const char *arg, void *data, unsigned sz)
return;
r = usb_read(download_base, len);
if ((r < 0) || (r != len)) {
if ((r < 0) || ((unsigned)r != len)) {
fastboot_state = STATE_ERROR;
return;
}
@ -271,12 +283,12 @@ static void cmd_download(const char *arg, void *data, unsigned sz)
fastboot_okay("");
}
static void fastboot_command_loop(void)
void fastboot_command_loop(void)
{
struct fastboot_cmd *cmd;
int r;
dprintf(INFO,"fastboot: processing commands\n");
//dprintf(INFO,"fastboot: processing commands\n");
//fastboot_sstat(1);
again:
while (fastboot_state != STATE_ERROR) {
r = usb_read(buffer, 64);
@ -299,10 +311,11 @@ again:
}
fastboot_state = STATE_OFFLINE;
dprintf(INFO,"fastboot: oops!\n");
//dprintf(INFO,"fastboot: oops!\n");
//fastboot_sstat(0);
}
static int fastboot_handler(void *arg)
int fastboot_handler(void *arg)
{
for (;;) {
event_wait(&usb_online);
@ -311,16 +324,21 @@ static int fastboot_handler(void *arg)
return 0;
}
static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
void fastboot_notify(struct udc_gadget *gadget, unsigned event)
{
if (event == UDC_EVENT_ONLINE) {
//c_usb_conn = 1;
//fastboot_sstat(1);
event_signal(&usb_online, 0);
} else if (event == UDC_EVENT_OFFLINE) {
//c_usb_conn = 0;
//fastboot_sstat(0);
}
}
static struct udc_endpoint *fastboot_endpoints[2];
struct udc_endpoint *fastboot_endpoints[2];
static struct udc_gadget fastboot_gadget = {
struct udc_gadget fastboot_gadget = {
.notify = fastboot_notify,
.ifc_class = 0xff,
.ifc_subclass = 0x42,
@ -333,7 +351,7 @@ static struct udc_gadget fastboot_gadget = {
int fastboot_init(void *base, unsigned size)
{
thread_t *thr;
dprintf(INFO, "fastboot_init()\n");
//dprintf(INFO, "fastboot_init()\n");
download_base = base;
download_max = size;
@ -360,7 +378,6 @@ int fastboot_init(void *base, unsigned size)
fastboot_register("getvar:", cmd_getvar);
fastboot_register("download:", cmd_download);
fastboot_publish("version", "0.5");
thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
thread_resume(thr);

View File

@ -30,7 +30,7 @@
#define __APP_FASTBOOT_H
int fastboot_init(void *xfer_buffer, unsigned max);
unsigned int fastboot_cstat(void);
/* register a command handler
* - command handlers will be called if their prefix matches
* - they are expected to call fastboot_okay() or fastboot_fail()
@ -46,5 +46,4 @@ void fastboot_publish(const char *name, const char *value);
void fastboot_okay(const char *result);
void fastboot_fail(const char *reason);
#endif

View File

@ -101,18 +101,19 @@ int set_recovery_message(const struct recovery_message *in)
n = pagesize * (MISC_COMMAND_PAGE + 1);
if (flash_read(ptn, offset, SCRATCH_ADDR, n)) {
if (flash_read(ptn, offset, (void *)SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
return -1;
}
offset += (pagesize * MISC_COMMAND_PAGE);
offset += SCRATCH_ADDR;
memcpy(offset, in, sizeof(*in));
memcpy((void *)offset, in, sizeof(*in));
if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: flash write fail!\n");
return -1;
}
return 1;
}
int read_update_header_for_bootloader(struct update_header *header)
@ -139,7 +140,7 @@ int read_update_header_for_bootloader(struct update_header *header)
}
memcpy(header, buf, sizeof(*header));
if(strncmp(header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
if(strncmp((char *)header->MAGIC, (char *)UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
{
return -1;
}
@ -170,7 +171,7 @@ int update_firmware_image (struct update_header *header, char *name)
offset += header->image_offset;
n = (header->image_length + pagemask) & (~pagemask);
if (flash_read(ptn, offset, SCRATCH_ADDR, n)) {
if (flash_read(ptn, offset, (void *)SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
return -1;
}
@ -181,7 +182,7 @@ int update_firmware_image (struct update_header *header, char *name)
return -1;
}
if (flash_write(ptn, 0, SCRATCH_ADDR, n)) {
if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
dprintf(CRITICAL, "ERROR: flash write fail!\n");
return -1;
}
@ -221,6 +222,11 @@ int update_firmware_image (struct update_header *header, char *name)
* It is recovery's responsibility to clean up the mess afterwards.
*/
int sdrecovery_init (void)
{
return 0;
}
extern unsigned boot_into_sboot;
int recovery_init (void)
{
struct recovery_message msg;
@ -231,12 +237,19 @@ int recovery_init (void)
// get recovery message
if(get_recovery_message(&msg))
return -1;
if (msg.command[0] != 0 && msg.command[0] != 255) {
dprintf("Recovery command: %.*s\n", sizeof(msg.command), msg.command);
if (((int)msg.command[0]) != (int)0 && ((int)msg.command[0]) != (int)255) {
//Debug Statement leading to warnings, will check lateron.
//dprintf("Recovery command: %.*s\n", (char *)sizeof(msg.command), msg.command);
}
msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
if (!strcmp("boot-recovery",msg.command)) {
if (!strcmp("boot-sboot",msg.command)) {
valid_command = 1;
strcpy(msg.command, ""); // to safe against multiple reboot into recovery
strcpy(msg.status, "OKAY");
set_recovery_message(&msg); // send recovery message
boot_into_sboot = 1; // Boot in sboot
return 0;
} else if (!strcmp("boot-recovery",msg.command)) {
valid_command = 1;
strcpy(msg.command, ""); // to safe against multiple reboot into recovery
strcpy(msg.status, "OKAY");

View File

@ -69,7 +69,7 @@ int set_recovery_message(const struct recovery_message *in);
int read_update_header_for_bootloader(struct update_header *header);
int update_firmware_image (struct update_header *header, char *name);
int sdrecovery_init (void);
int recovery_init (void);
extern unsigned boot_into_recovery;

View File

@ -51,16 +51,13 @@ void apps_init(void)
static int app_thread_entry(void *arg)
{
const struct app_descriptor *app = (const struct app_descriptor *)arg;
app->entry(app, NULL);
return 0;
}
static void start_app(const struct app_descriptor *app)
{
printf("starting app %s\n", app->name);
thread_resume(thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
}

View File

@ -2,4 +2,6 @@ LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/app.o
MODULES += \
lib/ptable \
lib/vptable

View File

@ -33,7 +33,6 @@ static void shell_entry(const struct app_descriptor *app, void *args)
{
console_start();
}
APP_START(shell)
.init = shell_init,
.entry = shell_entry,

View File

@ -64,8 +64,40 @@ void arch_early_init(void)
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_quiesce(void)
{
#if ARM_CPU_CORTEX_A8
/* disable the cycle count and performance counters */
uint32_t en;
__asm__ volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (en));
en &= ~1; /* disable all performance counters */
__asm__ volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (en));
/* disable cycle counter */
en = 0;
__asm__ volatile("mcr p15, 0, %0, c9, c12, 1" :: "r" (en));
#endif
#if ARM_CPU_ARM1136
/* disable the cycle count and performance counters */
uint32_t en;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (en));
en &= ~1; /* disable all performance counters */
__asm__ volatile("mcr p15, 0, %0, c15, c12, 0" :: "r" (en));
#endif
}
void arch_init(void)
{
}

View File

@ -318,17 +318,21 @@ invalidate_cache_v7:
/* shared cache flush routines */
/* void arch_flush_cache_range(addr_t start, size_t len); */
FUNCTION(arch_clean_cache_range)
0:
mcr p15, 0, r0, c7, c10, 1 // clean cache to PoC by MVA
add r0, r0, #CACHE_LINE
subs r1, r1, #CACHE_LINE
bhs 0b
FUNCTION(arch_clean_cache_range)
#if ARM_WITH_CP15
add r2, r0, r1 // calculate the end address
bic r0, #(CACHE_LINE-1) // align the start with a cache line
0:
mcr p15, 0, r0, c7, c10, 1 // clean cache to PoC by MVA
add r0, r0, #CACHE_LINE
cmp r0, r2
blo 0b
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 // data sync barrier
#endif
bx lr
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 // data sync barrier (formerly drain write buffer)
bx lr
/* void arch_flush_invalidate_cache_range(addr_t start, size_t len); */
FUNCTION(arch_clean_invalidate_cache_range)

View File

@ -35,6 +35,7 @@ void arm_mmu_init(void);
#define MMU_FLAG_BUFFERED 0x2
#define MMU_FLAG_READWRITE 0x4
void arm_mmu_map_section(addr_t paddr, addr_t vaddr, uint flags);
void arm_mmu_unmap_section(addr_t vaddr);
#if defined(__cplusplus)

View File

@ -42,11 +42,15 @@ static uint32_t *tt = (void *)MMU_TRANSLATION_TABLE_ADDR;
static uint32_t tt[4096] __ALIGNED(16384);
#endif
#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)
{
int index;
uint AP;
uint CB;
uint CB = 0;
uint TEX = 0;
#if defined(PLATFORM_MSM7K)
@ -69,6 +73,14 @@ void arm_mmu_map_section(addr_t paddr, addr_t vaddr, uint flags)
arm_invalidate_tlb();
}
void arm_mmu_unmap_section(addr_t vaddr)
{
uint index = vaddr / MB;
tt[index] = 0;
arm_invalidate_tlb();
}
void arm_mmu_init(void)
{
int i;

View File

@ -38,7 +38,8 @@ FUNCTION(arch_disable_ints)
msr cpsr_c, r0
bx lr
/* int atomic_swap(int *ptr, int val); */
/* THIS FUNCTION IS HIGHLY DEPRICIATED FROM ARMv6 ONWARDS. */
/* int atomic_swap(int *ptr, int val);*/
FUNCTION(atomic_swap)
swp r0, r2, [r1]
bx lr
@ -148,7 +149,7 @@ FUNCTION(atomic_or)
/* void arch_idle(); */
FUNCTION(arch_idle)
#if ARM_CPU_CORTEX_A8
.word 0xe320f003 /* wfi */
wfi /* wfi */
#elif PLATFORM_MSM7K
/* TODO: safely handle wfi */
#elif ARM_CPU_ARM1136 || ARM_CPU_ARM926
@ -201,13 +202,13 @@ FUNCTION(arm_invalidate_tlb)
FUNCTION(arch_switch_stacks_and_call)
mov sp, r1
bx r0
/*void dmb(void) */
FUNCTION(dmb)
#if ARM_CPU_CORTEX_A8
dmb sy
#elif ARM_CPU_ARM1136
mov r0, #0
mcr p15, 0, r0, c7, c10, 5
#endif
bx lr
/* 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

View File

@ -6,6 +6,10 @@ SECTIONS
{
. = %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 @@ SECTIONS
.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);

View File

@ -6,6 +6,10 @@ SECTIONS
{
. = %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,8 +37,6 @@ SECTIONS
.init : { *(.init) } =0x9090
.plt : { *(.plt) }
/* text/read-only data */
.text : { *(.text .text.* .glue_7* .gnu.linkonce.t.*) } =0x9090
.rodata : {
*(.rodata .rodata.* .gnu.linkonce.r.*)

View File

@ -1,138 +1,290 @@
/*
* Copyright (c) 2008, Google Inc.
* All rights reserved.
*
* Copyright (c) 2009-2010, 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE 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 <debug.h>
#include <err.h>
#include <stdlib.h>
#include <dev/fbcon.h>
#include "font5x12.h"
#include <string.h>
#include <splash.h>
#include "font5x12.h"
/* Cartesian coordinate system */
struct pos {
int x;
int y;
};
/* fbconfig, retrieved using fbcon_display() in device instants */
static struct fbcon_config *config = NULL;
#define RGB565_BLACK 0x0000
#define RGB565_RED 0xf800
#define RGB565_GREEN 0x07e0
#define RGB565_BLUE 0x001f
#define RGB565_YELLOW 0xffe0
#define RGB565_CYAN 0x07ff
#define RGB565_MAGENTA 0xf81f
#define RGB565_WHITE 0xffff
#define RGB565_BLACK 0x0000
#define RGB565_lboot 0x02E0
#define RGB888_BLACK 0x000000
#define RGB888_WHITE 0xffffff
#define FONT_WIDTH 5
#define FONT_HEIGHT 12
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 800
static uint16_t BGCOLOR;
static uint16_t FGCOLOR;
static uint16_t TGCOLOR;
static uint16_t F1COLOR;
static uint16_t T1COLOR;
static struct pos cur_pos;
static struct pos max_pos;
static bool scrolled;
static bool forcedtg;
void fbcon_forcetg(bool flag_boolean)
{
forcedtg = flag_boolean;
}
static void ijustscrolled(void){
scrolled = true;
}
static void cleanedyourcrap(void){
scrolled = false;
}
bool didyouscroll(void){
return scrolled;
}
void fill_screen(uint16_t COLOR)
{
memset(config->base, COLOR, (((config->width) * (config->height)) * (config->bpp /8)));
return;
}
void fbcon_clear_region(int start_y, int end_y){
unsigned area_size = (((end_y - start_y) * FONT_HEIGHT) * config->width) * ((config->bpp) / 8);
unsigned start_offset = ((start_y * FONT_HEIGHT) * config->width) * ((config->bpp) / 8);
memset(config->base + start_offset, BGCOLOR, area_size);
}
int fbcon_get_y_cord(void){
return cur_pos.y;
}
void fbcon_set_y_cord(int offset){
cur_pos.y = offset;
}
int fbcon_get_x_cord(void){
return cur_pos.x;
}
void fbcon_set_x_cord(int offset){
cur_pos.x = offset;
}
static void fbcon_drawglyph(uint16_t *pixels, uint16_t paint, unsigned stride,
unsigned *glyph)
{
/* x -> loop counter for X axis, y -> loop counter for Y axis, data -> Holder for the font data */
unsigned x, y, data;
stride -= FONT_WIDTH;
/* Pixels required to jump to the pixel right below the current one. */
stride -= (1 + FONT_WIDTH ); /* 1 spacing pixel + Font Width */
/* Do TextGroundcolor ? False by default, we don't want to waste cpu cycle(s) overwriting the same data over and over again. */
bool dtg = false;
/* Background color mismatches with Foreground-Background Color OR the Forced TextGround flag is set to True */
if((BGCOLOR != TGCOLOR)||(forcedtg)){dtg=true;}
/*
1) Hex code picked randomly from the list in font header
0x084211c0, 0x00071084,
2) Decoded into 4 bit binary
8421 8421 8421 8421 8421 8421 8421 8421 8421 8421 8421 8421 8421 8421 8421 8421
0000 1000 0100 0010 0001 0001 1100 0000 0000 0000 0000 0111 0001 0000 1000 0100
3) Hex Value lookup
0 00
1 01
2 02
3 03
4 04
5 05
6 06
7 07
8 08
9 09
a 10
b 11
c 12
d 13
e 14
f 15
4) Decoded "glyph"
glyph[0] = 00001000010000100001000111000000
glyph[1] = 00000000000001110001000010000100
*/
data = glyph[0];
for (y = 0; y < (FONT_HEIGHT / 2); ++y) {
for (x = 0; x < FONT_WIDTH; ++x) {
if (data & 1)
*pixels = paint;
data >>= 1;
pixels++;
for (y = 0; y < (FONT_HEIGHT / 2); ++y) { // What does this mean ? Why split the glyph into 2 parts ?
if(dtg){
*pixels=TGCOLOR; // If mismatch or forced, write pixel tg color
}
pixels += stride;
}
data = glyph[1];
for (y = 0; y < (FONT_HEIGHT / 2); y++) {
for (x = 0; x < FONT_WIDTH; x++) {
if (data & 1)
pixels++; // Advance one pixel so Actual font width = 6 (1 spacing bit + 5 font bits)
for (x = 0; x < FONT_WIDTH; ++x) { // Again, whats the diff with ++x and x++ ? will lookup
if (data & 1){ // BITWISE AND, so if *data = 1 then print paint else print bg(skip data write to pixel)OR tgcolor.
*pixels = paint;
data >>= 1;
/* For a single assignment memset will prove to be more costly than a simple pointer assignment
compared to fill_screen, clear screen where we assign values to MASS number of pointers. */
} else if(dtg){
*pixels=TGCOLOR; // If mismatch or forced, write pixel tg color
}
data >>= 1; // Shift 1 bit to right
pixels++;
// pixel pointer++ to the next pixel (we processed 1 pixel in our row, goto next.
// There should be 5 loops.
// 1 Row complete. Height left to print = 12 ((FontHeight)) - 1*(loop_counter)
}
pixels += stride;
pixels += stride; // Get to the pixel right below the 1st pixel in our current row
}
data = glyph[1]; // Switch data to the Next glyph data
for (y = 0; y < (FONT_HEIGHT / 2); y++) { // Does it make much of a difference ?
if(dtg){
*pixels=TGCOLOR; // If mismatch or forced, write pixel tg color
}
pixels++; // Advance one pixel so Actual font width = 6 (1 spacing bit + 5 font bits)
for (x = 0; x < FONT_WIDTH; x++) { // Again, whats the diff with ++x and x++ ? will lookup
if (data & 1){ // BITWISE AND, so if *data = 1 then print paint else print bg(skip data write to pixel)OR tgcolor.
*pixels = paint; // Fill pixel with paint
} else if(dtg){
*pixels=TGCOLOR; // If mismatch or forced, write pixel tg color
}
data >>= 1; // Shift right 1 bit
pixels++; // Shift right 1 pixel
}
pixels += stride; // Get to the pixel right below the 1st pixel in our current row
// So the pointer stops at the bottom right corner of the glyph
// it writes the glyph in the following manner ->
/*
I think i went wrong somewhere (What do the 4 extra bits do ? and if they are never used, why even assign them value in font header ?)
:/ Damn coffee.
(spacing pixel) 01 02 03 04 05
(spacing pixel) 06 07 08 09 10
(spacing pixel) 11 12 13 14 15
(spacing pixel) 16 17 18 19 20
(spacing pixel) 21 22 23 24 25
(spacing pixel) 26 27 28 29 30
Switch to glyph[1]
(spacing pixel) 31 32 33 34 35
(spacing pixel) 36 37 38 39 40
(spacing pixel) 41 42 43 44 45
(spacing pixel) 46 47 48 49 50
(spacing pixel) 51 52 53 54 55
(spacing pixel) 56 57 58 59 60
*/
}
/* Done drawing a char */
}
static void fbcon_flush(void)
void fbcon_flush(void)
{
/* Send update command and hold pointer till really done */
if (config->update_start)
config->update_start();
if (config->update_done)
while (!config->update_done());
}
/* TODO: Take stride into account */
void fbcon_push(void)
{
/* Send update command and return immediately */
if (config->update_start)
config->update_start();
return (void)config->update_done;
}
/* TODO: Do not scroll the Androids */
static void fbcon_scroll_up(void)
{
unsigned short *dst = config->base;
unsigned short *src = dst + (config->width * FONT_HEIGHT);
unsigned count = config->width * (config->height - FONT_HEIGHT);
while(count--) {
*dst++ = *src++;
}
count = config->width * FONT_HEIGHT;
while(count--) {
*dst++ = BGCOLOR;
}
fbcon_flush();
ijustscrolled();
unsigned buffer_size = (config->width * (config->height - SPLASH_IMAGE_HEIGHT)) * (config->bpp /8);
unsigned line_size = (config->width * FONT_HEIGHT) * (config->bpp / 8);
// copy framebuffer from base + 1 line
memmove(config->base, config->base + line_size, buffer_size-line_size);
// clear last framebuffer line
memset(config->base+buffer_size-line_size,BGCOLOR,line_size);
// Flush holds the control till the Display is REALLY updated, now we update the display data and move on instead of blocking the pointer there and save some time as this function is HIGHLY time critical.
fbcon_push();
}
/* TODO: take stride into account */
void fbcon_clear(void)
{
unsigned count = config->width * config->height;
memset(config->base, BGCOLOR, count * ((config->bpp) / 8));
}
{
/* Clear the console, only till the part where logo is displayed */
unsigned image_base = (((((config->height) - (SPLASH_IMAGE_HEIGHT ))) *
(config->width)) + (config->width/2 - (SPLASH_IMAGE_WIDTH / 2)));
/* Set the LCD to BGCOLOR till the image base */
memset(config->base, BGCOLOR, image_base * ((config->bpp) / 8));
/* memset ( TARGET, DATA, Sizeof ); */
}
static void fbcon_set_colors(unsigned bg, unsigned fg)
{
BGCOLOR = bg;
F1COLOR = FGCOLOR;
FGCOLOR = fg;
}
void fbcon_setfg(unsigned fg)
{
F1COLOR = FGCOLOR;
FGCOLOR = fg;
}
void fbcon_setbg(unsigned bg)
{
BGCOLOR = bg;
fbcon_disp_logo();
}
void fbcon_settg(unsigned tg)
{
T1COLOR = TGCOLOR;
TGCOLOR = tg;
}
void fbcon_set_txt_colors(unsigned fgcolor, unsigned tgcolor){
F1COLOR = FGCOLOR;
T1COLOR = TGCOLOR;
FGCOLOR = fgcolor;
TGCOLOR = tgcolor;
}
uint16_t fbcon_get_bgcol(void)
{
return BGCOLOR;
}
void fbcon_reset_colors_rgb555(void)
{
uint16_t bg;
uint16_t fg;
fg = RGB565_BLACK;
bg = RGB565_WHITE;
fbcon_set_colors(bg, fg);
T1COLOR = (TGCOLOR = bg);
F1COLOR = fg;
}
void fbcon_putc(char c)
{
uint16_t *pixels;
/* ignore anything that happens before fbcon is initialized */
if (!config)
return;
@ -148,9 +300,9 @@ void fbcon_putc(char c)
pixels = config->base;
pixels += cur_pos.y * FONT_HEIGHT * config->width;
pixels += cur_pos.x * (FONT_WIDTH + 1);
fbcon_drawglyph(pixels, FGCOLOR, config->stride,
font5x12 + (c - 32) * 2);
pixels += cur_pos.x * (FONT_WIDTH + 1 );
fbcon_drawglyph(pixels, FGCOLOR, config->stride, font5x12 + (c - 32) * 2);
cur_pos.x++;
if (cur_pos.x < max_pos.x)
@ -165,7 +317,6 @@ newline:
} else
fbcon_flush();
}
void fbcon_setup(struct fbcon_config *_config)
{
uint32_t bg;
@ -177,25 +328,28 @@ void fbcon_setup(struct fbcon_config *_config)
switch (config->format) {
case FB_FORMAT_RGB565:
fg = RGB565_WHITE;
bg = RGB565_BLACK;
fg = RGB565_BLACK;
bg = RGB565_WHITE;
break;
case FB_FORMAT_RGB888:
fg = RGB888_WHITE;
bg = RGB888_BLACK;
break;
case FB_FORMAT_RGB888:
fg = RGB888_WHITE;
bg = RGB888_BLACK;
break;
default:
dprintf(CRITICAL, "unknown framebuffer pixel format\n");
ASSERT(0);
break;
}
T1COLOR = (TGCOLOR = bg);
F1COLOR = fg;
//SGCOLOR = 0x001f;
fbcon_set_colors(bg, fg);
cur_pos.x = 0;
cur_pos.y = 0;
max_pos.x = config->width / (FONT_WIDTH+1);
max_pos.y = (config->height - 1) / FONT_HEIGHT;
max_pos.y = (config->height - SPLASH_IMAGE_HEIGHT) / FONT_HEIGHT;
cleanedyourcrap();
fbcon_disp_logo();
#if !DISPLAY_SPLASH_SCREEN
fbcon_clear();
#endif
@ -206,40 +360,37 @@ struct fbcon_config* fbcon_display(void)
return config;
}
void diplay_image_on_screen(void)
void fbcon_resetdisp(void){
fbcon_clear();
cur_pos.x = 0;
cur_pos.y = 0;
cleanedyourcrap();
}
void fbcon_disp_logo(void)
{
unsigned i = 0;
unsigned total_x = config->width;
unsigned total_y = config->height;
unsigned bytes_per_bpp = ((config->bpp) / 8);
unsigned image_base = ((((total_y/2) - (SPLASH_IMAGE_WIDTH / 2) - 1) *
(config->width)) + (total_x/2 - (SPLASH_IMAGE_HEIGHT / 2)));
fbcon_clear();
unsigned image_base = ((((config->height)-SPLASH_IMAGE_HEIGHT) * (config->width)) + ((config->width/2)-(SPLASH_IMAGE_WIDTH/2)));
//Set the LCD to BGCOLOR from the image base to image size
memset(config->base + ((((config->height)-(SPLASH_IMAGE_HEIGHT))*(config->width))*bytes_per_bpp), BGCOLOR, (((SPLASH_IMAGE_HEIGHT) * config->width)*bytes_per_bpp));
#if DISPLAY_TYPE_MIPI
if (bytes_per_bpp == 3)
{
for (i = 0; i < SPLASH_IMAGE_WIDTH; i++)
for (i = 0; i < SPLASH_IMAGE_HEIGHT; i++)
{
memcpy (config->base + ((image_base + (i * (config->width))) * bytes_per_bpp),
imageBuffer_rgb888 + (i * SPLASH_IMAGE_HEIGHT * bytes_per_bpp),
SPLASH_IMAGE_HEIGHT * bytes_per_bpp);
imageBuffer_rgb888 + (i * SPLASH_IMAGE_WIDTH * bytes_per_bpp),
SPLASH_IMAGE_WIDTH * bytes_per_bpp);
}
}
if (bytes_per_bpp == 2)
{
for (i = 0; i < SPLASH_IMAGE_HEIGHT; i++)
{
memcpy (config->base + ((image_base + (i * (config->width))) * 2),
imageBuffer + (i * SPLASH_IMAGE_WIDTH * 2),
SPLASH_IMAGE_WIDTH * 2);
}
}
}
fbcon_flush();
if(is_cmd_mode_enabled())
mipi_dsi_cmd_mode_trigger();
#else
if (bytes_per_bpp == 2)
{
for (i = 0; i < SPLASH_IMAGE_WIDTH; i++)
{
memcpy (config->base + ((image_base + (i * (config->width))) * bytes_per_bpp),
imageBuffer + (i * SPLASH_IMAGE_HEIGHT * bytes_per_bpp),
SPLASH_IMAGE_HEIGHT * bytes_per_bpp);
}
}
fbcon_flush();
#endif
}

View File

@ -28,7 +28,7 @@
unsigned font5x12[] = {
0x00000000, 0x00000000,
0x08421080, 0x00020084,
0x08421080, 0x00020084,
0x00052940, 0x00000000,
0x15f52800, 0x0000295f,
0x1c52f880, 0x00023e94,

View File

@ -62,7 +62,7 @@ struct gpio_qwerty_kp {
};
static struct gpio_qwerty_kp *qwerty_keypad;
/* TODO: Support multiple keypads? */
/* TODO(Not Needed): Support multiple keypads? maybe for other platforms but for HD2, this serves no purposes and can be looked into lateron. */
static struct gpio_kp *keypad;
static void check_output(struct gpio_kp *kp, int out, int polarity)
@ -605,7 +605,7 @@ void pmic_write(unsigned address, unsigned data)
write_func wr_function = &i2c_ssbi_write_bytes;
if(wr_function == NULL)
return;
if ((*wr_function)(&data, 1, address))
if ((*wr_function)((unsigned char *)&data, 1, address))
dprintf (CRITICAL, "Error in initializing register\n");
}

View File

@ -40,7 +40,6 @@ void keys_init(void)
{
memset(key_bitmap, 0, sizeof(key_bitmap));
}
void keys_post_event(uint16_t code, int16_t value)
{
if (code >= MAX_KEYS) {
@ -56,7 +55,7 @@ void keys_post_event(uint16_t code, int16_t value)
// dprintf(INFO, "key state change: %d %d\n", code, value);
}
int keys_get_state_n(uint16_t code){return bitmap_test(key_bitmap,code);}
int keys_get_state(uint16_t code)
{
if (code >= MAX_KEYS) {

View File

@ -29,9 +29,11 @@ extern "C" {
void arch_early_init(void);
void arch_init(void);
void arch_quiesce(void);
#if defined(__cplusplus)
}
#endif
/* arch specific bits */
#include <arch/defines.h>
#endif

View File

@ -51,12 +51,15 @@ void arch_enable_cache(uint flags);
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);
void arch_disable_mmu(void);
void arch_switch_stacks_and_call(addr_t call, addr_t stack) __NO_RETURN;
uint32_t arch_cycle_count(void);
#if defined(__cplusplus)
}

View File

@ -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)
@ -105,5 +118,6 @@
#endif
#endif
/* TODO: add type check */
#define countof(a) (sizeof(a) / sizeof((a)[0]))
#endif

View File

@ -57,7 +57,7 @@ int _dvprintf(const char *fmt, va_list ap);
#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;

48
lk/include/dev/display.h Normal file
View File

@ -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

View File

@ -28,11 +28,18 @@
* SUCH DAMAGE.
*/
#ifndef __DEV_FBCON_H
#ifdef __DEV_FBCON_H
#undef __DEV_FBCON_H
#endif
#define __DEV_FBCON_H
#define FB_FORMAT_RGB565 0
#define FB_FORMAT_RGB888 1
#ifndef FB_FORMAT_RGB565
#define FB_FORMAT_RGB565 1
#endif
#ifndef FB_FORMAT_RGB888
#define FB_FORMAT_RGB888 0
#endif
struct fbcon_config {
void *base;
@ -41,14 +48,32 @@ struct fbcon_config {
unsigned stride;
unsigned bpp;
unsigned format;
void (*update_start)(void);
int (*update_done)(void);
};
struct fbcon_config* fbcon_display(void);
int fbcon_get_y_cord(void);
int fbcon_get_x_cord(void);
uint16_t fbcon_get_bgcol(void);
bool didyouscroll(void);
void fbcon_setup(struct fbcon_config *cfg);
void fbcon_putc(char c);
void fbcon_clear(void);
struct fbcon_config* fbcon_display(void);
#endif /* __DEV_FBCON_H */
void fbcon_resetdisp(void);
void fbcon_flush(void);
void fbcon_push(void);
void fbcon_setfg(unsigned fg);
void fbcon_setbg(unsigned bg);
void fbcon_settg(unsigned tg);
void fbcon_disp_logo(void);
void fbcon_clear_region(int start_y, int end_y);
void fbcon_set_y_cord(int offset);
void fbcon_set_x_cord(int offset);
void fbcon_inits(char *amss_ver, char *Menuid);
void fill_screen(uint16_t COLOR);
void fbcon_set_txt_colors(unsigned fgcolor, unsigned tgcolor);
void fbcon_reset_colors_rgb555(void);
void fbcon_forcetg(bool flag_boolean);

View File

@ -83,9 +83,9 @@
#define KEY_MENU 0x124
#define MAX_KEYS 0x1ff
void keys_init(void);
void keys_post_event(uint16_t code, int16_t value);
int keys_get_state_n(uint16_t code);
int keys_get_state(uint16_t code);
#endif /* __DEV_KEYS_H */

179
lk/include/dev/pci.h Normal file
View File

@ -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

View File

@ -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

View File

@ -58,6 +58,7 @@ status_t event_wait(event_t *);
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

View File

@ -104,6 +104,7 @@ void thread_set_priority(int priority);
thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size);
status_t thread_resume(thread_t *);
void thread_exit(int retcode) __NO_RETURN;
void thread_kill(thread_t *) __NO_RETURN;
void thread_sleep(time_t delay);
void dump_thread(thread_t *t);
@ -205,7 +206,11 @@ int wait_queue_wake_all(wait_queue_t *, bool reschedule, status_t wait_queue_err
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;

40
lk/include/lib/bcache.h Normal file
View File

@ -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

81
lk/include/lib/bio.h Normal file
View File

@ -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

42
lk/include/lib/cbuf.h Normal file
View File

@ -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

View File

@ -31,6 +31,7 @@ typedef struct {
const char *str;
unsigned int u;
int i;
bool b;
} cmd_args;
typedef int (*console_cmd)(int argc, const cmd_args *argv);
@ -52,11 +53,23 @@ typedef struct _cmd_block {
#define STATIC_COMMAND_START static const cmd _cmd_list[] = {
#define STATIC_COMMAND_END(name) }; const cmd_block _cmd_block_##name __SECTION(".commands")= { NULL, sizeof(_cmd_list) / sizeof(_cmd_list[0]), _cmd_list }
#define STATIC_COMMAND_START_NAMED(name) static const cmd _cmd_list_##name[] = {
#define STATIC_COMMAND_END_NAMED(name) }; const cmd_block _cmd_block_##name __SECTION(".commands")= { NULL, sizeof(_cmd_list_##name) / sizeof(_cmd_list_##name[0]), _cmd_list_##name }
#define STATIC_COMMAND(command_str, help_str, func) { command_str, help_str, func },
#define COMMAND_BLOCK_INIT_ITEM(cmd_block_ptr, cmd_ptr) {(cmd_block_ptr)->next = NULL; (cmd_block_ptr)->count = 1; (cmd_block_ptr)->list = cmd_ptr;}
/* external api */
int console_init(void);
void console_start(void);
void console_register_commands(cmd_block *block);
int console_run_command(const char *string);
int console_run_script(const char *string);
int console_run_script_locked(const char *string); // special case from inside a command
console_cmd console_get_command_handler(const char *command);
void console_abort_script(void);
extern int lastresult;
#endif

12
lk/include/lib/font.h Normal file
View File

@ -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

52
lk/include/lib/fs.h Normal file
View File

@ -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

42
lk/include/lib/fs/ext2.h Normal file
View File

@ -0,0 +1,42 @@
/*
* 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 __EXT2_H
#define __EXT2_H
#include <lib/bio.h>
#include <lib/fs.h>
typedef void *fsfilecookie;
int ext2_mount(bdev_t *dev, fscookie *cookie);
int ext2_unmount(fscookie cookie);
/* file api */
int ext2_open_file(fscookie cookie, const char *path, fsfilecookie *fcookie);
int ext2_read_file(fsfilecookie fcookie, void *buf, off_t offset, size_t len);
int ext2_close_file(fsfilecookie fcookie);
int ext2_stat_file(fsfilecookie fcookie, struct file_stat *);
#endif

86
lk/include/lib/gfx.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

14
lk/include/lib/text.h Normal file
View File

@ -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

10
lk/include/lib/tga.h Normal file
View File

@ -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

46
lk/include/lib/vptable.h Normal file
View File

@ -0,0 +1,46 @@
/*
Variable Partition table definition
vptable is virtual configuration partition with settings and partition layout configuration
Copyright (c) 2011 - Danijel Posilovic - dan1j3l
*/
extern int atoi ( const char * str );
extern struct ptable *flash_get_vptable(void);
struct part_def {
char name[32]; // partition name (identifier in mtd device)
short size; // size in blocks 1Mb = 8 Blocks
bool asize; // autosize and use all available space 1=yes 0=no
};
struct vpartitions{
char tag[7];
struct part_def pdef[12];
short extrom_enabled;
};
static const int MAX_NUM_PART =12;
struct vpartitions vparts;
unsigned blk_pmb;
unsigned flash_size_blk;
unsigned vpart_available_size();
int read_vptable(struct vpartitions *output);
int write_vptable(const struct vpartitions *input);
int vpart_variable_exist();
int vpart_partition_exist(const char* pName);
void vpart_resize_asize();
void vpart_add(const char *pData);
void vpart_restruct();
void vpart_del(const char *pName);
void vpart_list();
void vpart_clear();
void vpart_create_default();
void init_vpart();
void vpart_commit();
void vpart_read();
void vpart_enable_extrom();
void vpart_disable_extrom();
void vpart_resize(const char *pData);

View File

@ -27,5 +27,8 @@ typedef enum handler_return (*platform_timer_callback)(void *arg, time_t now);
status_t platform_set_periodic_timer(platform_timer_callback callback, void *arg, time_t interval);
void mdelay(unsigned msecs);
void udelay(unsigned usecs);
#endif

View File

@ -60,6 +60,11 @@ typedef unsigned long time_t;
typedef unsigned long long bigtime_t;
#define INFINITE_TIME ULONG_MAX
#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,

View File

@ -1,7 +1,9 @@
#ifndef __VERSION_H
#define __VERSION_H
static const char *cLK_version = "1.4.0.1";
#ifdef __VERSION_H
#undef __VERSION_H
#endif
#define __VERSION_H
//static const char *HBOOT_version = "cLK-1.0";
//static const char *HBOOT_version_short = "1.0";
static char *BUILD_DATE="Aug 08 2011, 18:06:51";
static char *PSUEDO_VERSION = "1.4.0.1";

View File

@ -26,7 +26,7 @@
#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 +35,11 @@ static int cmd_threadload(int argc, const cmd_args *argv);
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,7 +75,6 @@ static enum handler_return threadload(struct timer *t, time_t now, void *arg)
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) {
@ -108,7 +107,7 @@ static int cmd_threadload(int argc, const cmd_args *argv)
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);

View File

@ -120,6 +120,14 @@ static int bootstrap2(void *arg)
dprintf(SPEW, "top of bootstrap2()\n");
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");

View File

@ -49,9 +49,9 @@ void mutex_destroy(mutex_t *m)
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;

View File

@ -61,6 +61,11 @@ thread_t *idle_thread;
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)
{
@ -181,6 +186,22 @@ static void thread_cleanup_dpc(void *thread)
free(t);
}
void thread_kill(thread_t *thread)
{
thread_t *t = (thread_t *)thread;
#if THREAD_CHECKS
ASSERT(t->magic == THREAD_MAGIC);
ASSERT(t->state == THREAD_RUNNING);
#endif
enter_critical_section();
t->state = THREAD_DEATH;
t->retcode = 0;
dpc_queue(thread_cleanup_dpc, (void *)t, DPC_FLAG_NORESCHED);
thread_resched();
list_delete(&t->thread_list_node);
exit_critical_section();
panic("somehow fell through thread_exit()\n");
}
void thread_exit(int retcode)
{
#if THREAD_CHECKS
@ -394,14 +415,11 @@ static enum handler_return thread_sleep_handler(timer_t *timer, time_t now, void
void thread_sleep(time_t delay)
{
timer_t timer;
#if THREAD_CHECKS
ASSERT(current_thread->magic == THREAD_MAGIC);
ASSERT(current_thread->state == THREAD_RUNNING);
#endif
timer_initialize(&timer);
enter_critical_section();
timer_set_oneshot(&timer, delay, thread_sleep_handler, (void *)current_thread);
current_thread->state = THREAD_SLEEPING;
@ -434,6 +452,9 @@ void thread_init_early(void)
void thread_init(void)
{
#if PLATFORM_HAS_DYNAMIC_TIMER
timer_initialize(&preempt_timer);
#endif
}
void thread_set_name(const char *name)
@ -661,6 +682,4 @@ status_t thread_unblock_from_wait_queue(thread_t *t, bool reschedule, status_t w
exit_critical_section();
return NO_ERROR;
}
}

View File

@ -44,7 +44,8 @@ static void insert_timer_in_queue(timer_t *timer)
timer_t *entry;
list_for_every_entry(&timer_queue, entry, timer_t, node) {
if (entry->scheduled_time > timer->scheduled_time) {
//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 +55,11 @@ static void insert_timer_in_queue(timer_t *timer)
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 +69,7 @@ void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, vo
now = current_time();
timer->scheduled_time = now + delay;
timer->periodic_time = 0;
timer->periodic_time = period;
timer->callback = callback;
timer->arg = arg;
@ -78,17 +79,69 @@ void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, vo
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();
}
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);
}
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);
}
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();
}
@ -106,7 +159,8 @@ static enum handler_return timer_tick(void *arg, time_t 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 || now < timer->scheduled_time))
if (likely(!timer || TIME_LT(now, timer->scheduled_time)))
break;
/* process it */
@ -119,15 +173,40 @@ static enum handler_return timer_tick(void *arg, time_t now)
thread_stats.timers++;
#endif
// TRACEF("firing callback %p, arg %p\n", timer->callback, timer->arg);
if (timer->callback(timer, now, timer->arg) == INT_RESCHEDULE)
ret = INT_RESCHEDULE;
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));
/* let the scheduler have a shot to do quantum expiration, etc */
if (thread_timer_tick() == INT_RESCHEDULE)
ret = INT_RESCHEDULE;
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;
}

348
lk/lib/bcache/bcache.c Normal file
View File

@ -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);
}

6
lk/lib/bcache/rules.mk Normal file
View File

@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += lib/bio
OBJS += \
$(LOCAL_DIR)/bcache.o

445
lk/lib/bio/bio.c Normal file
View File

@ -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);
}

192
lk/lib/bio/debug.c Normal file
View File

@ -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

101
lk/lib/bio/mem.c Normal file
View File

@ -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;
}

9
lk/lib/bio/rules.mk Normal file
View File

@ -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

112
lk/lib/bio/subdev.c Normal file
View File

@ -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;
}

146
lk/lib/cbuf/cbuf.c Normal file
View File

@ -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;
}

4
lk/lib/cbuf/rules.mk Normal file
View File

@ -0,0 +1,4 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/cbuf.o

View File

@ -25,8 +25,39 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <kernel/thread.h>
#include <kernel/mutex.h>
#include <lib/console.h>
#if WITH_LIB_ENV
#include <lib/env.h>
#endif
#define LINE_LEN 512
#define HISTORY_LEN 16
#define LOCAL_TRACE 0
/* debug buffer */
static char *debug_buffer;
/* command processor state */
static mutex_t *command_lock;
int lastresult;
static bool abort_script;
/* command history stuff */
static char *history; // HISTORY_LEN rows of LINE_LEN chars a piece
static uint history_next;
static void init_history(void);
static void add_history(const char *line);
static uint start_history_cursor(void);
static const char *next_history(uint *cursor);
static const char *prev_history(uint *cursor);
static void dump_history(void);
/* list of installed commands */
static cmd_block *command_list = NULL;
/* a linear array of statically defined command blocks,
@ -37,15 +68,22 @@ extern cmd_block __commands_end;
static int cmd_help(int argc, const cmd_args *argv);
static int cmd_test(int argc, const cmd_args *argv);
static int cmd_history(int argc, const cmd_args *argv);
STATIC_COMMAND_START
{ "help", "this list", &cmd_help },
{ "test", "test the command processor", &cmd_test },
STATIC_COMMAND("help", "this list", &cmd_help)
#if DEBUGLEVEL > 1
STATIC_COMMAND("test", "test the command processor", &cmd_test)
STATIC_COMMAND("history", "command history", &cmd_history)
#endif
STATIC_COMMAND_END(help);
int console_init(void)
{
printf("console_init: entry\n");
LTRACE_ENTRY;
command_lock = malloc(sizeof(mutex_t));
mutex_init(command_lock);
/* add all the statically defined commands to the list */
cmd_block *block;
@ -53,8 +91,100 @@ int console_init(void)
console_register_commands(block);
}
init_history();
return 0;
}
static int cmd_history(int argc, const cmd_args *argv)
{
dump_history();
return 0;
}
static inline char *history_line(uint line)
{
return history + line * LINE_LEN;
}
static inline uint ptrnext(uint ptr)
{
return (ptr + 1) % HISTORY_LEN;
}
static inline uint ptrprev(uint ptr)
{
return (ptr - 1) % HISTORY_LEN;
}
static void dump_history(void)
{
printf("command history:\n");
uint ptr = ptrprev(history_next);
int i;
for (i=0; i < HISTORY_LEN; i++) {
if (history_line(ptr)[0] != 0)
printf("\t%s\n", history_line(ptr));
ptr = ptrprev(ptr);
}
}
static void init_history(void)
{
/* allocate and set up the history buffer */
history = calloc(1, HISTORY_LEN * LINE_LEN);
history_next = 0;
}
static void add_history(const char *line)
{
// reject some stuff
if (line[0] == 0)
return;
uint last = ptrprev(history_next);
if (strcmp(line, history_line(last)) == 0)
return;
strlcpy(history_line(history_next), line, LINE_LEN);
history_next = ptrnext(history_next);
}
static uint start_history_cursor(void)
{
return ptrprev(history_next);
}
static const char *next_history(uint *cursor)
{
uint i = ptrnext(*cursor);
if (i == history_next)
return ""; // can't let the cursor hit the head
*cursor = i;
return history_line(i);
}
static const char *prev_history(uint *cursor)
{
uint i;
const char *str = history_line(*cursor);
/* if we are already at head, stop here */
if (*cursor == history_next)
return str;
/* back up one */
i = ptrprev(*cursor);
/* if the next one is gonna be null */
if (history_line(i)[0] == '\0')
return str;
/* update the cursor */
*cursor = i;
return str;
}
static const cmd *match_command(const char *command)
{
@ -73,11 +203,13 @@ static const cmd *match_command(const char *command)
return NULL;
}
static int read_line(char *buffer, int len)
static int read_debug_line(const char **outbuffer, void *cookie)
{
int pos = 0;
int escape_level = 0;
uint history_cursor = start_history_cursor();
char *buffer = debug_buffer;
for (;;) {
char c;
@ -85,13 +217,13 @@ static int read_line(char *buffer, int len)
if (getc(&c) < 0)
continue;
// printf("c = 0x%hhx\n", c);
// TRACEF("c = 0x%hhx\n", c);
if (escape_level == 0) {
switch (c) {
case '\r':
case '\n':
putc(c);
putc('\n');
goto done;
case 0x7f: // backspace or delete
@ -134,18 +266,31 @@ static int read_line(char *buffer, int len)
puts("\x1b[1D"); // move to the left one
}
break;
case 65: // up arrow
case 66: // down arrow
// XXX do history here
break;
default:
break;
case 65: // up arrow -- previous history
case 66: // down arrow -- next history
// wipe out the current line
while (pos > 0) {
pos--;
puts("\x1b[1D"); // move to the left one
putc(' ');
puts("\x1b[1D"); // move to the left one
}
if (c == 65)
strlcpy(buffer, prev_history(&history_cursor), LINE_LEN);
else
strlcpy(buffer, next_history(&history_cursor), LINE_LEN);
pos = strlen(buffer);
puts(buffer);
break;
default:
break;
}
escape_level = 0;
}
/* end of line. */
if (pos == (len - 1)) {
if (pos == (LINE_LEN - 1)) {
puts("\nerror: line too long\n");
pos = 0;
goto done;
@ -153,27 +298,46 @@ static int read_line(char *buffer, int len)
}
done:
// printf("returning pos %d\n", pos);
// dprintf("returning pos %d\n", pos);
buffer[pos] = 0;
return pos;
// null terminate
buffer[pos] = 0;
// add to history
add_history(buffer);
// return a pointer to our buffer
*outbuffer = buffer;
return pos;
}
static int tokenize_command(char *buffer, cmd_args *args, int arg_count)
static int tokenize_command(const char *inbuffer, const char **continuebuffer, char *buffer, size_t buflen, cmd_args *args, int arg_count)
{
int pos;
int inpos;
int outpos;
int arg;
bool finished;
enum {
INITIAL = 0,
IN_SPACE,
IN_TOKEN
} state;
enum {
INITIAL = 0,
NEXT_FIELD,
SPACE,
IN_SPACE,
TOKEN,
IN_TOKEN,
QUOTED_TOKEN,
IN_QUOTED_TOKEN,
VAR,
IN_VAR,
COMMAND_SEP,
} state;
char varname[128];
int varnamepos;
pos = 0;
arg = 0;
state = INITIAL;
finished = false;
inpos = 0;
outpos = 0;
varnamepos = 0;
state = INITIAL;
*continuebuffer = NULL;
for (;;) {
char c = buffer[pos];
@ -185,41 +349,140 @@ static int tokenize_command(char *buffer, cmd_args *args, int arg_count)
switch (state) {
case INITIAL:
if (isspace(c)) {
state = IN_SPACE;
case NEXT_FIELD:
if (c == '\0')
goto done;
if (isspace(c))
state = SPACE;
else if (c == ';')
state = COMMAND_SEP;
else
state = TOKEN;
break;
case SPACE:
state = IN_SPACE;
break;
case IN_SPACE:
if (c == '\0')
goto done;
if (c == ';') {
state = COMMAND_SEP;
} else if (!isspace(c)) {
state = TOKEN;
} else {
state = IN_TOKEN;
args[arg].str = &buffer[pos];
inpos++; // consume the space
}
break;
case TOKEN:
// start of a token
DEBUG_ASSERT(c != '\0');
if (c == '"') {
// start of a quoted token
state = QUOTED_TOKEN;
} else if (c == '$') {
// start of a variable
state = VAR;
} else {
// regular, unquoted token
state = IN_TOKEN;
args[arg].str = &buffer[outpos];
}
break;
case IN_TOKEN:
if (finished) {
if (c == '\0') {
arg++;
goto done;
}
if (isspace(c)) {
if (isspace(c) || c == ';') {
arg++;
buffer[pos] = 0;
buffer[outpos] = 0;
outpos++;
/* are we out of tokens? */
if (arg == arg_count)
goto done;
state = IN_SPACE;
state = NEXT_FIELD;
} else {
buffer[outpos] = c;
outpos++;
inpos++;
}
pos++;
break;
case IN_SPACE:
if (finished)
goto done;
if (!isspace(c)) {
state = IN_TOKEN;
args[arg].str = &buffer[pos];
case QUOTED_TOKEN:
// start of a quoted token
DEBUG_ASSERT(c == '"');
state = IN_QUOTED_TOKEN;
args[arg].str = &buffer[outpos];
inpos++; // consume the quote
break;
case IN_QUOTED_TOKEN:
if (c == '\0') {
arg++;
goto done;
}
if (c == '"') {
arg++;
buffer[outpos] = 0;
outpos++;
/* are we out of tokens? */
if (arg == arg_count)
goto done;
state = NEXT_FIELD;
}
buffer[outpos] = c;
outpos++;
inpos++;
break;
case VAR:
DEBUG_ASSERT(c == '$');
state = IN_VAR;
args[arg].str = &buffer[outpos];
inpos++; // consume the dollar sign
// initialize the place to store the variable name
varnamepos = 0;
break;
case IN_VAR:
if (c == '\0' || isspace(c) || c == ';') {
// hit the end of variable, look it up and stick it inline
varname[varnamepos] = 0;
#if WITH_LIB_ENV
int rc = env_get(varname, &buffer[outpos], buflen - outpos);
#else
int rc = -1;
#endif
if (rc < 0) {
buffer[outpos++] = '0';
buffer[outpos++] = 0;
} else {
outpos += strlen(&buffer[outpos]) + 1;
}
arg++;
/* are we out of tokens? */
if (arg == arg_count)
goto done;
state = NEXT_FIELD;
} else {
varname[varnamepos] = c;
varnamepos++;
inpos++;
}
pos++;
break;
case COMMAND_SEP:
// we hit a ;, so terminate the command and pass the remainder of the command back in continuebuffer
DEBUG_ASSERT(c == ';');
inpos++; // consume the ';'
*continuebuffer = &inbuffer[inpos];
goto done;
}
}
done:
buffer[outpos] = 0;
return arg;
}
@ -230,37 +493,60 @@ static void convert_args(int argc, cmd_args *argv)
for (i = 0; i < argc; i++) {
argv[i].u = atoui(argv[i].str);
argv[i].i = atoi(argv[i].str);
if (!strcmp(argv[i].str, "true") || !strcmp(argv[i].str, "on")) {
argv[i].b = true;
} else if (!strcmp(argv[i].str, "false") || !strcmp(argv[i].str, "off")) {
argv[i].b = false;
} else {
argv[i].b = (argv[i].u == 0) ? false : true;
}
}
}
static void console_loop(void)
static void command_loop(int (*get_line)(const char **, void *), void *get_line_cookie, bool showprompt, bool locked)
{
bool exit;
bool report_result;
cmd_args args[16];
char buffer[256];
const char *buffer;
const char *continuebuffer;
char *outbuf;
printf("entering main console loop\n");
const size_t outbuflen = 1024;
outbuf = malloc(outbuflen);
for (;;) {
puts("] ");
exit = false;
continuebuffer = NULL;
while (!exit) {
// read a new line if it hadn't been split previously and passed back from tokenize_command
if (continuebuffer == NULL) {
if (showprompt)
puts("] ");
int len = read_line(buffer, sizeof(buffer));
if (len == 0)
continue;
// printf("line = '%s'\n", buffer);
int len = get_line(&buffer, get_line_cookie);
if (len < 0)
break;
if (len == 0)
continue;
} else {
buffer = continuebuffer;
}
// dprintf("line = '%s'\n", buffer);
/* tokenize the line */
int argc = tokenize_command(buffer, args, 16);
int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen, args, 16);
if (argc < 0) {
printf("syntax error\n");
if (showprompt)
printf("syntax error\n");
continue;
} else if (argc == 0) {
continue;
}
// printf("after tokenize: argc %d\n", argc);
// dprintf("after tokenize: argc %d\n", argc);
// for (int i = 0; i < argc; i++)
// printf("%d: '%s'\n", i, args[i].str);
// dprintf("%d: '%s'\n", i, args[i].str);
/* convert the args */
convert_args(argc, args);
@ -268,42 +554,126 @@ static void console_loop(void)
/* try to match the command */
const cmd *command = match_command(args[0].str);
if (!command) {
printf("command not found\n");
if (showprompt)
printf("command not found\n");
continue;
}
int result = command->cmd_callback(argc, args);
if (!locked)
mutex_acquire(command_lock);
// XXX do something with the result
abort_script = false;
lastresult = command->cmd_callback(argc, args);
#if WITH_LIB_ENV
if ((env_get_bool("reportresult", &report_result, false) >= 0) &&
(report_result))
{
if (lastresult < 0)
printf("FAIL %d\n", lastresult);
else
printf("PASS %d\n", lastresult);
}
#endif
#if WITH_LIB_ENV
// stuff the result in an environment var
env_set_int("?", lastresult, true);
#endif
// someone must have aborted the current script
if (abort_script)
exit = true;
abort_script = false;
if (!locked)
mutex_release(command_lock);
}
free(outbuf);
}
void console_abort_script(void)
{
abort_script = true;
}
void console_start(void)
{
debug_buffer = malloc(LINE_LEN);
console_loop();
dprintf(INFO, "entering main console loop\n");
for (;;)
command_loop(&read_debug_line, NULL, true, false);
}
int console_run_command(const char *string)
struct line_read_struct {
const char *string;
int pos;
char *buffer;
size_t buflen;
};
static int fetch_next_line(const char **buffer, void *cookie)
{
const cmd *command;
ASSERT(string != NULL);
command = match_command(string);
if (!command)
struct line_read_struct *lineread = (struct line_read_struct *)cookie;
// we're done
if (lineread->string[lineread->pos] == 0)
return -1;
int result = command->cmd_callback(0, NULL);
size_t bufpos = 0;
while (lineread->string[lineread->pos] != 0) {
if (lineread->string[lineread->pos] == '\n') {
lineread->pos++;
break;
}
if (bufpos == (lineread->buflen - 1))
break;
lineread->buffer[bufpos] = lineread->string[lineread->pos];
lineread->pos++;
bufpos++;
}
lineread->buffer[bufpos] = 0;
return result;
*buffer = lineread->buffer;
return bufpos;
}
static int console_run_script_etc(const char *string, bool locked)
{
struct line_read_struct lineread;
lineread.string = string;
lineread.pos = 0;
lineread.buffer = malloc(LINE_LEN);
lineread.buflen = LINE_LEN;
command_loop(&fetch_next_line, (void *)&lineread, false, locked);
return lastresult;
}
int console_run_script(const char *string)
{
return console_run_script_etc(string, false);
}
int console_run_script_locked(const char *string)
{
return console_run_script_etc(string, true);
}
console_cmd console_get_command_handler(const char *commandstr)
{
const cmd *command = match_command(commandstr);
if (command)
return command->cmd_callback;
else
return NULL;
}
void console_register_commands(cmd_block *block)
{
ASSERT(block);
ASSERT(block->next == NULL);
DEBUG_ASSERT(block);
DEBUG_ASSERT(block->next == NULL);
block->next = command_list;
command_list = block;
@ -320,21 +690,22 @@ static int cmd_help(int argc, const cmd_args *argv)
for (block = command_list; block != NULL; block = block->next) {
const cmd *curr_cmd = block->list;
for (i = 0; i < block->count; i++) {
printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str ? curr_cmd[i].help_str : "");
if (curr_cmd[i].help_str)
printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str);
}
}
return 0;
}
#if DEBUGLEVEL > 1
static int cmd_test(int argc, const cmd_args *argv)
{
int i;
printf("argc %d, argv %p\n", argc, argv);
for (i = 0; i < argc; i++)
printf("\t%d: str '%s', i %d, u %#x\n", i, argv[i].str, argv[i].i, argv[i].u);
printf("\t%d: str '%s', i %d, u %#x, b %d\n", i, argv[i].str, argv[i].i, argv[i].u, argv[i].b);
return 0;
}
#endif

View File

@ -31,7 +31,6 @@
#include <platform.h>
#include <platform/debug.h>
#include <kernel/thread.h>
#include <kernel/timer.h>
void spin(uint32_t usecs)
{
@ -71,12 +70,8 @@ int _dputs(const char *str)
int _dprintf(const char *fmt, ...)
{
char buf[256];
char ts_buf[13];
int err;
snprintf(ts_buf, sizeof(ts_buf), "[%u] ", current_time());
dputs(ALWAYS, ts_buf);
va_list ap;
va_start(ap, fmt);
err = vsnprintf(buf, sizeof(buf), fmt, ap);

62
lk/lib/font/font.c Normal file
View File

@ -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);
}

136
lk/lib/font/font.h Normal file
View File

@ -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

6
lk/lib/font/rules.mk Normal file
View File

@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += lib/gfx
OBJS += \
$(LOCAL_DIR)/font.o

237
lk/lib/fs/debug.c Normal file
View File

@ -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

198
lk/lib/fs/ext2/dir.c Normal file
View File

@ -0,0 +1,198 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include <debug.h>
#include <err.h>
#include <lib/fs/ext2.h>
#include "ext2_priv.h"
#define LOCAL_TRACE 0
/* read in the dir, look for the entry */
static int ext2_dir_lookup(ext2_t *ext2, struct ext2_inode *dir_inode, const char *name, inodenum_t *inum)
{
uint file_blocknum;
int err;
uint8_t *buf;
size_t namelen = strlen(name);
if (!S_ISDIR(dir_inode->i_mode))
return ERR_NOT_DIR;
buf = malloc(EXT2_BLOCK_SIZE(ext2->sb));
file_blocknum = 0;
for (;;) {
/* read in the offset */
err = ext2_read_inode(ext2, dir_inode, buf, file_blocknum * EXT2_BLOCK_SIZE(ext2->sb), EXT2_BLOCK_SIZE(ext2->sb));
if (err <= 0) {
free(buf);
return -1;
}
/* walk through the directory entries, looking for the one that matches */
struct ext2_dir_entry_2 *ent;
uint pos = 0;
while (pos < EXT2_BLOCK_SIZE(ext2->sb)) {
ent = (struct ext2_dir_entry_2 *)&buf[pos];
LTRACEF("ent %d:%d: inode 0x%x, reclen %d, namelen %d\n",
file_blocknum, pos, LE32(ent->inode), LE16(ent->rec_len), ent->name_len/* , ent->name*/);
/* sanity check the record length */
if (LE16(ent->rec_len) == 0)
break;
if (ent->name_len == namelen && memcmp(name, ent->name, ent->name_len) == 0) {
// match
*inum = LE32(ent->inode);
LTRACEF("match: inode %d\n", *inum);
free(buf);
return 1;
}
pos += ROUNDUP(LE16(ent->rec_len), 4);
}
file_blocknum++;
/* sanity check the directory. 4MB should be enough */
if (file_blocknum > 1024) {
free(buf);
return -1;
}
}
}
/* note, trashes path */
static int ext2_walk(ext2_t *ext2, char *path, struct ext2_inode *start_inode, inodenum_t *inum, int recurse)
{
char *ptr;
struct ext2_inode inode;
struct ext2_inode dir_inode;
int err;
bool done;
LTRACEF("path '%s', start_inode %p, inum %p, recurse %d\n", path, start_inode, inum, recurse);
if (recurse > 4)
return ERR_RECURSE_TOO_DEEP;
/* chew up leading slashes */
ptr = &path[0];
while (*ptr == '/')
ptr++;
done = false;
memcpy(&dir_inode, start_inode, sizeof(struct ext2_inode));
while (!done) {
/* process the first component */
char *next_sep = strchr(ptr, '/');
if (next_sep) {
/* terminate the next component, giving us a substring */
*next_sep = 0;
} else {
/* this is the last component */
done = true;
}
LTRACEF("component '%s', done %d\n", ptr, done);
/* do the lookup on this component */
err = ext2_dir_lookup(ext2, &dir_inode, ptr, inum);
if (err < 0)
return err;
nextcomponent:
LTRACEF("inum %u\n", *inum);
/* load the next inode */
err = ext2_load_inode(ext2, *inum, &inode);
if (err < 0)
return err;
/* is it a symlink? */
if (S_ISLNK(inode.i_mode)) {
char link[512];
LTRACEF("hit symlink\n");
err = ext2_read_link(ext2, &inode, link, sizeof(link));
if (err < 0)
return err;
LTRACEF("symlink read returns %d '%s'\n", err, link);
/* recurse, parsing the link */
if (link[0] == '/') {
/* link starts with '/', so start over again at the rootfs */
err = ext2_walk(ext2, link, &ext2->root_inode, inum, recurse + 1);
} else {
err = ext2_walk(ext2, link, &dir_inode, inum, recurse + 1);
}
LTRACEF("recursive walk returns %d\n", err);
if (err < 0)
return err;
/* if we weren't done with our path parsing, start again with the result of this recurse */
if (!done) {
goto nextcomponent;
}
} else if (S_ISDIR(inode.i_mode)) {
/* for the next cycle, point the dir inode at our new directory */
memcpy(&dir_inode, &inode, sizeof(struct ext2_inode));
} else {
if (!done) {
/* we aren't done and this walked over a nondir, abort */
LTRACEF("not finished and component is nondir\n");
return ERR_NOT_FOUND;
}
}
if (!done) {
/* move to the next seperator */
ptr = next_sep + 1;
/* consume multiple seperators */
while (*ptr == '/')
ptr++;
}
}
return 0;
}
/* do a path parse, looking up each component */
int ext2_lookup(ext2_t *ext2, const char *_path, inodenum_t *inum)
{
LTRACEF("path '%s', inum %p\n", _path, inum);
char path[512];
strlcpy(path, _path, sizeof(path));
return ext2_walk(ext2, path, &ext2->root_inode, inum, 1);
}

259
lk/lib/fs/ext2/ext2.c Normal file
View File

@ -0,0 +1,259 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include <debug.h>
#include <lib/fs/ext2.h>
#include "ext2_priv.h"
#define LOCAL_TRACE 0
static void endian_swap_superblock(struct ext2_super_block *sb)
{
LE32SWAP(sb->s_inodes_count);
LE32SWAP(sb->s_blocks_count);
LE32SWAP(sb->s_r_blocks_count);
LE32SWAP(sb->s_free_blocks_count);
LE32SWAP(sb->s_free_inodes_count);
LE32SWAP(sb->s_first_data_block);
LE32SWAP(sb->s_log_block_size);
LE32SWAP(sb->s_log_frag_size);
LE32SWAP(sb->s_blocks_per_group);
LE32SWAP(sb->s_frags_per_group);
LE32SWAP(sb->s_inodes_per_group);
LE32SWAP(sb->s_mtime);
LE32SWAP(sb->s_wtime);
LE16SWAP(sb->s_mnt_count);
LE16SWAP(sb->s_max_mnt_count);
LE16SWAP(sb->s_magic);
LE16SWAP(sb->s_state);
LE16SWAP(sb->s_errors);
LE16SWAP(sb->s_minor_rev_level);
LE32SWAP(sb->s_lastcheck);
LE32SWAP(sb->s_checkinterval);
LE32SWAP(sb->s_creator_os);
LE32SWAP(sb->s_rev_level);
LE16SWAP(sb->s_def_resuid);
LE16SWAP(sb->s_def_resgid);
LE32SWAP(sb->s_first_ino);
LE16SWAP(sb->s_inode_size);
LE16SWAP(sb->s_block_group_nr);
LE32SWAP(sb->s_feature_compat);
LE32SWAP(sb->s_feature_incompat);
LE32SWAP(sb->s_feature_ro_compat);
LE32SWAP(sb->s_algorithm_usage_bitmap);
/* ext3 journal stuff */
LE32SWAP(sb->s_journal_inum);
LE32SWAP(sb->s_journal_dev);
LE32SWAP(sb->s_last_orphan);
LE32SWAP(sb->s_default_mount_opts);
LE32SWAP(sb->s_first_meta_bg);
}
static void endian_swap_inode(struct ext2_inode *inode)
{
LE16SWAP(inode->i_mode);
LE16SWAP(inode->i_uid_low);
LE32SWAP(inode->i_size);
LE32SWAP(inode->i_atime);
LE32SWAP(inode->i_ctime);
LE32SWAP(inode->i_mtime);
LE32SWAP(inode->i_dtime);
LE16SWAP(inode->i_gid_low);
LE16SWAP(inode->i_links_count);
LE32SWAP(inode->i_blocks);
LE32SWAP(inode->i_flags);
// leave block pointers/symlink data alone
LE32SWAP(inode->i_generation);
LE32SWAP(inode->i_file_acl);
LE32SWAP(inode->i_dir_acl);
LE32SWAP(inode->i_faddr);
LE16SWAP(inode->i_uid_high);
LE16SWAP(inode->i_gid_high);
}
static void endian_swap_group_desc(struct ext2_group_desc *gd)
{
LE32SWAP(gd->bg_block_bitmap);
LE32SWAP(gd->bg_inode_bitmap);
LE32SWAP(gd->bg_inode_table);
LE16SWAP(gd->bg_free_blocks_count);
LE16SWAP(gd->bg_free_inodes_count);
LE16SWAP(gd->bg_used_dirs_count);
}
int ext2_mount(bdev_t *dev, fscookie *cookie)
{
int err;
LTRACEF("dev %p\n", dev);
ext2_t *ext2 = malloc(sizeof(ext2_t));
ext2->dev = dev;
err = bio_read(dev, &ext2->sb, 1024, sizeof(struct ext2_super_block));
if (err < 0)
goto err;
endian_swap_superblock(&ext2->sb);
/* see if the superblock is good */
if (ext2->sb.s_magic != EXT2_SUPER_MAGIC) {
err = -1;
return err;
}
/* calculate group count, rounded up */
ext2->s_group_count = (ext2->sb.s_blocks_count + ext2->sb.s_blocks_per_group - 1) / ext2->sb.s_blocks_per_group;
/* print some info */
LTRACEF("rev level %d\n", ext2->sb.s_rev_level);
LTRACEF("compat features 0x%x\n", ext2->sb.s_feature_compat);
LTRACEF("incompat features 0x%x\n", ext2->sb.s_feature_incompat);
LTRACEF("ro compat features 0x%x\n", ext2->sb.s_feature_ro_compat);
LTRACEF("block size %d\n", EXT2_BLOCK_SIZE(ext2->sb));
LTRACEF("inode size %d\n", EXT2_INODE_SIZE(ext2->sb));
LTRACEF("block count %d\n", ext2->sb.s_blocks_count);
LTRACEF("blocks per group %d\n", ext2->sb.s_blocks_per_group);
LTRACEF("group count %d\n", ext2->s_group_count);
LTRACEF("inodes per group %d\n", ext2->sb.s_inodes_per_group);
/* we only support dynamic revs */
if (ext2->sb.s_rev_level > EXT2_DYNAMIC_REV) {
err = -2;
return err;
}
/* make sure it doesn't have any ro features we don't support */
if (ext2->sb.s_feature_ro_compat & ~(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
err = -3;
return err;
}
/* read in all the group descriptors */
ext2->gd = malloc(sizeof(struct ext2_group_desc) * ext2->s_group_count);
err = bio_read(ext2->dev, (void *)ext2->gd,
(EXT2_BLOCK_SIZE(ext2->sb) == 4096) ? 4096 : 2048,
sizeof(struct ext2_group_desc) * ext2->s_group_count);
if (err < 0) {
err = -4;
return err;
}
int i;
for (i=0; i < ext2->s_group_count; i++) {
endian_swap_group_desc(&ext2->gd[i]);
LTRACEF("group %d:\n", i);
LTRACEF("\tblock bitmap %d\n", ext2->gd[i].bg_block_bitmap);
LTRACEF("\tinode bitmap %d\n", ext2->gd[i].bg_inode_bitmap);
LTRACEF("\tinode table %d\n", ext2->gd[i].bg_inode_table);
LTRACEF("\tfree blocks %d\n", ext2->gd[i].bg_free_blocks_count);
LTRACEF("\tfree inodes %d\n", ext2->gd[i].bg_free_inodes_count);
LTRACEF("\tused dirs %d\n", ext2->gd[i].bg_used_dirs_count);
}
/* initialize the block cache */
ext2->cache = bcache_create(ext2->dev, EXT2_BLOCK_SIZE(ext2->sb), 4);
/* load the first inode */
err = ext2_load_inode(ext2, EXT2_ROOT_INO, &ext2->root_inode);
if (err < 0)
goto err;
// TRACE("successfully mounted volume\n");
*cookie = ext2;
return 0;
err:
LTRACEF("exiting with err code %d\n", err);
free(ext2);
return err;
}
int ext2_unmount(fscookie cookie)
{
// free it up
ext2_t *ext2 = (ext2_t *)cookie;
bcache_destroy(ext2->cache);
free(ext2->gd);
free(ext2);
return 0;
}
static void get_inode_addr(ext2_t *ext2, inodenum_t num, blocknum_t *block, size_t *block_offset)
{
num--;
uint32_t group = num / ext2->sb.s_inodes_per_group;
// calculate the start of the inode table for the group it's in
*block = ext2->gd[group].bg_inode_table;
// add the offset of the inode within the group
size_t offset = (num % EXT2_INODES_PER_GROUP(ext2->sb)) * EXT2_INODE_SIZE(ext2->sb);
*block_offset = offset % EXT2_BLOCK_SIZE(ext2->sb);
*block += offset / EXT2_BLOCK_SIZE(ext2->sb);
}
int ext2_load_inode(ext2_t *ext2, inodenum_t num, struct ext2_inode *inode)
{
int err;
LTRACEF("num %d, inode %p\n", num, inode);
blocknum_t bnum;
size_t block_offset;
get_inode_addr(ext2, num, &bnum, &block_offset);
LTRACEF("bnum %u, offset %zd\n", bnum, block_offset);
/* get a pointer to the cache block */
void *cache_ptr;
err = bcache_get_block(ext2->cache, &cache_ptr, bnum);
if (err < 0)
return err;
/* copy the inode out */
memcpy(inode, (uint8_t *)cache_ptr + block_offset, sizeof(struct ext2_inode));
/* put the cache block */
bcache_put_block(ext2->cache, bnum);
/* endian swap it */
endian_swap_inode(inode);
LTRACEF("read inode: mode 0x%x, size %d\n", inode->i_mode, inode->i_size);
return 0;
}

436
lk/lib/fs/ext2/ext2_fs.h Normal file
View File

@ -0,0 +1,436 @@
/*
* linux/include/linux/ext2_fs.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/include/linux/minix_fs.h
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#ifndef _LINUX_EXT2_FS_H
#define _LINUX_EXT2_FS_H
#include <sys/types.h>
#include <stdint.h>
//#include <linux/types.h>
//#include <linux/magic.h>
/*
* The second extended filesystem constants/structures
*/
/*
* Special inode numbers
*/
#define EXT2_BAD_INO 1 /* Bad blocks inode */
#define EXT2_ROOT_INO 2 /* Root inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
/* First non-reserved inode for old ext2 filesystems */
#define EXT2_GOOD_OLD_FIRST_INO 11
/*
* Maximal count of links to a file
*/
#define EXT2_LINK_MAX 32000
/*
* Macro-instructions used to manage several block sizes
*/
#define EXT2_MIN_BLOCK_SIZE 1024
#define EXT2_MAX_BLOCK_SIZE 4096
#define EXT2_MIN_BLOCK_LOG_SIZE 10
#define EXT2_BLOCK_SIZE(s) ((uint32_t)EXT2_MIN_BLOCK_SIZE << (s).s_log_block_size)
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (uint32_t))
#define EXT2_BLOCK_SIZE_BITS(s) ((s).s_log_block_size + 10)
#define EXT2_INODE_SIZE(s) (((s).s_rev_level == EXT2_GOOD_OLD_REV) ? \
EXT2_GOOD_OLD_INODE_SIZE : \
(s).s_inode_size)
#define EXT2_FIRST_INO(s) (((s).s_rev_level == EXT2_GOOD_OLD_REV) ? \
EXT2_GOOD_OLD_FIRST_INO : \
(s).s_first_ino)
/*
* Macro-instructions used to manage fragments
*/
#define EXT2_MIN_FRAG_SIZE 1024
#define EXT2_MAX_FRAG_SIZE 4096
#define EXT2_MIN_FRAG_LOG_SIZE 10
#define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s).s_log_frag_size)
#define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
uint32_t bg_block_bitmap; /* Blocks bitmap block */
uint32_t bg_inode_bitmap; /* Inodes bitmap block */
uint32_t bg_inode_table; /* Inodes table block */
uint16_t bg_free_blocks_count; /* Free blocks count */
uint16_t bg_free_inodes_count; /* Free inodes count */
uint16_t bg_used_dirs_count; /* Directories count */
uint16_t bg_pad;
uint32_t bg_reserved[3];
};
/*
* Macro-instructions used to manage group descriptors
*/
#define EXT2_BLOCKS_PER_GROUP(s) ((s).s_blocks_per_group)
#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
#define EXT2_INODES_PER_GROUP(s) ((s).s_inodes_per_group)
/*
* Constants relative to the data blocks
*/
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
uint16_t i_mode; /* File mode */
uint16_t i_uid; /* Low 16 bits of Owner Uid */
uint32_t i_size; /* Size in bytes */
uint32_t i_atime; /* Access time */
uint32_t i_ctime; /* Creation time */
uint32_t i_mtime; /* Modification time */
uint32_t i_dtime; /* Deletion Time */
uint16_t i_gid; /* Low 16 bits of Group Id */
uint16_t i_links_count; /* Links count */
uint32_t i_blocks; /* Blocks count */
uint32_t i_flags; /* File flags */
union {
struct {
uint32_t l_i_reserved1;
} linux1;
struct {
uint32_t h_i_translator;
} hurd1;
struct {
uint32_t m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
uint32_t i_generation; /* File version (for NFS) */
uint32_t i_file_acl; /* File ACL */
uint32_t i_dir_acl; /* Directory ACL */
uint32_t i_faddr; /* Fragment address */
union {
struct {
uint8_t l_i_frag; /* Fragment number */
uint8_t l_i_fsize; /* Fragment size */
uint16_t i_pad1;
uint16_t l_i_uid_high; /* these 2 fields */
uint16_t l_i_gid_high; /* were reserved2[0] */
uint32_t l_i_reserved2;
} linux2;
struct {
uint8_t h_i_frag; /* Fragment number */
uint8_t h_i_fsize; /* Fragment size */
uint16_t h_i_mode_high;
uint16_t h_i_uid_high;
uint16_t h_i_gid_high;
uint32_t h_i_author;
} hurd2;
struct {
uint8_t m_i_frag; /* Fragment number */
uint8_t m_i_fsize; /* Fragment size */
uint16_t m_pad1;
uint32_t m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
#define i_size_high i_dir_acl
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
#define i_fsize osd2.linux2.l_i_fsize
#define i_uid_low i_uid
#define i_gid_low i_gid
#define i_uid_high osd2.linux2.l_i_uid_high
#define i_gid_high osd2.linux2.l_i_gid_high
#define i_reserved2 osd2.linux2.l_i_reserved2
/*
* File system states
*/
#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
/*
* Mount flags
*/
#define EXT2_MOUNT_CHECK 0x000001 /* Do mount-time checks */
#define EXT2_MOUNT_OLDALLOC 0x000002 /* Don't use the new Orlov allocator */
#define EXT2_MOUNT_GRPID 0x000004 /* Create files with directory's group */
#define EXT2_MOUNT_DEBUG 0x000008 /* Some debugging messages */
#define EXT2_MOUNT_ERRORS_CONT 0x000010 /* Continue on errors */
#define EXT2_MOUNT_ERRORS_RO 0x000020 /* Remount fs ro on errors */
#define EXT2_MOUNT_ERRORS_PANIC 0x000040 /* Panic on errors */
#define EXT2_MOUNT_MINIX_DF 0x000080 /* Mimics the Minix statfs */
#define EXT2_MOUNT_NOBH 0x000100 /* No buffer_heads */
#define EXT2_MOUNT_NO_UID32 0x000200 /* Disable 32-bit UIDs */
#define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */
#define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */
#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */
#define EXT2_MOUNT_USRQUOTA 0x020000 /* user quota */
#define EXT2_MOUNT_GRPQUOTA 0x040000 /* group quota */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
EXT2_MOUNT_##opt)
/*
* Maximal mount counts between two filesystem checks
*/
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
/*
* Behaviour when detecting errors
*/
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
#define EXT2_ERRORS_PANIC 3 /* Panic */
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
#define EXT2_SUPER_MAGIC 0xEF53
#define EXT3_SUPER_MAGIC 0xEF53
#define EXT4_SUPER_MAGIC 0xEF53
/*
* Structure of the super block
*/
struct ext2_super_block {
uint32_t s_inodes_count; /* Inodes count */
uint32_t s_blocks_count; /* Blocks count */
uint32_t s_r_blocks_count; /* Reserved blocks count */
uint32_t s_free_blocks_count; /* Free blocks count */
uint32_t s_free_inodes_count; /* Free inodes count */
uint32_t s_first_data_block; /* First Data Block */
uint32_t s_log_block_size; /* Block size */
uint32_t s_log_frag_size; /* Fragment size */
uint32_t s_blocks_per_group; /* # Blocks per group */
uint32_t s_frags_per_group; /* # Fragments per group */
uint32_t s_inodes_per_group; /* # Inodes per group */
uint32_t s_mtime; /* Mount time */
uint32_t s_wtime; /* Write time */
uint16_t s_mnt_count; /* Mount count */
uint16_t s_max_mnt_count; /* Maximal mount count */
uint16_t s_magic; /* Magic signature */
uint16_t s_state; /* File system state */
uint16_t s_errors; /* Behaviour when detecting errors */
uint16_t s_minor_rev_level; /* minor revision level */
uint32_t s_lastcheck; /* time of last check */
uint32_t s_checkinterval; /* max. time between checks */
uint32_t s_creator_os; /* OS */
uint32_t s_rev_level; /* Revision level */
uint16_t s_def_resuid; /* Default uid for reserved blocks */
uint16_t s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
uint32_t s_first_ino; /* First non-reserved inode */
uint16_t s_inode_size; /* size of inode structure */
uint16_t s_block_group_nr; /* block group # of this superblock */
uint32_t s_feature_compat; /* compatible feature set */
uint32_t s_feature_incompat; /* incompatible feature set */
uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
uint8_t s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
uint32_t s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
uint16_t s_padding1;
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
uint32_t s_journal_inum; /* inode number of journal file */
uint32_t s_journal_dev; /* device number of journal file */
uint32_t s_last_orphan; /* start of list of inodes to delete */
uint32_t s_hash_seed[4]; /* HTREE hash seed */
uint8_t s_def_hash_version; /* Default hash version to use */
uint8_t s_reserved_char_pad;
uint16_t s_reserved_word_pad;
uint32_t s_default_mount_opts;
uint32_t s_first_meta_bg; /* First metablock block group */
uint32_t s_reserved[190]; /* Padding to the end of the block */
};
/*
* Codes for operating systems
*/
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
#define EXT2_OS_FREEBSD 3
#define EXT2_OS_LITES 4
/*
* Revision levels
*/
#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
#define EXT2_GOOD_OLD_INODE_SIZE 128
/*
* Feature set definitions
*/
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
( (sb).s_feature_compat & cpu_to_le32(mask) )
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
( (sb).s_feature_ro_compat & cpu_to_le32(mask) )
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
( (sb).s_feature_incompat & cpu_to_le32(mask) )
#define EXT2_SET_COMPAT_FEATURE(sb,mask) \
(sb).s_feature_compat |= cpu_to_le32(mask)
#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \
(sb).s_feature_ro_compat |= cpu_to_le32(mask)
#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \
(sb).s_feature_incompat |= cpu_to_le32(mask)
#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \
(sb).s_feature_compat &= ~cpu_to_le32(mask)
#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
(sb).s_feature_ro_compat &= ~cpu_to_le32(mask)
#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
(sb).s_feature_incompat &= ~cpu_to_le32(mask)
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010
#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
#define EXT2_FEATURE_COMPAT_ANY 0xffffffff
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff
#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
#define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
EXT2_FEATURE_INCOMPAT_META_BG)
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP
#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
/*
* Default values for user and/or group using reserved blocks
*/
#define EXT2_DEF_RESUID 0
#define EXT2_DEF_RESGID 0
/*
* Default mount options
*/
#define EXT2_DEFM_DEBUG 0x0001
#define EXT2_DEFM_BSDGROUPS 0x0002
#define EXT2_DEFM_XATTR_USER 0x0004
#define EXT2_DEFM_ACL 0x0008
#define EXT2_DEFM_UID16 0x0010
/* Not used by ext2, but reserved for use by ext3 */
#define EXT3_DEFM_JMODE 0x0060
#define EXT3_DEFM_JMODE_DATA 0x0020
#define EXT3_DEFM_JMODE_ORDERED 0x0040
#define EXT3_DEFM_JMODE_WBACK 0x0060
/*
* Structure of a directory entry
*/
#define EXT2_NAME_LEN 255
struct ext2_dir_entry {
uint32_t inode; /* Inode number */
uint16_t rec_len; /* Directory entry length */
uint16_t name_len; /* Name length */
char name[EXT2_NAME_LEN]; /* File name */
};
/*
* The new version of the directory entry. Since EXT2 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext2_dir_entry_2 {
uint32_t inode; /* Inode number */
uint16_t rec_len; /* Directory entry length */
uint8_t name_len; /* Name length */
uint8_t file_type;
char name[EXT2_NAME_LEN]; /* File name */
};
/*
* Ext2 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
enum {
EXT2_FT_UNKNOWN,
EXT2_FT_REG_FILE,
EXT2_FT_DIR,
EXT2_FT_CHRDEV,
EXT2_FT_BLKDEV,
EXT2_FT_FIFO,
EXT2_FT_SOCK,
EXT2_FT_SYMLINK,
EXT2_FT_MAX
};
/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
*/
#define EXT2_DIR_PAD 4
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
#endif /* _LINUX_EXT2_FS_H */

View File

@ -0,0 +1,90 @@
/*
* 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 __EXT2_PRIV_H
#define __EXT2_PRIV_H
#include <lib/bio.h>
#include <lib/bcache.h>
#include "ext2_fs.h"
typedef uint32_t blocknum_t;
typedef uint32_t inodenum_t;
typedef uint32_t groupnum_t;
typedef struct {
bdev_t *dev;
bcache_t cache;
struct ext2_super_block sb;
int s_group_count;
struct ext2_group_desc *gd;
struct ext2_inode root_inode;
} ext2_t;
struct cache_block {
blocknum_t num;
void *ptr;
};
/* open file handle */
typedef struct {
ext2_t *ext2;
struct cache_block ind_cache[3]; // cache of indirect blocks as they're scanned
struct ext2_inode inode;
} ext2_file_t;
/* internal routines */
int ext2_load_inode(ext2_t *ext2, inodenum_t num, struct ext2_inode *inode);
int ext2_lookup(ext2_t *ext2, const char *path, inodenum_t *inum); // path to inode
/* io */
int ext2_read_block(ext2_t *ext2, void *buf, blocknum_t bnum);
int ext2_get_block(ext2_t *ext2, void **ptr, blocknum_t bnum);
int ext2_put_block(ext2_t *ext2, blocknum_t bnum);
off_t ext2_file_len(ext2_t *ext2, struct ext2_inode *inode);
int ext2_read_inode(ext2_t *ext2, struct ext2_inode *inode, void *buf, off_t offset, size_t len);
int ext2_read_link(ext2_t *ext2, struct ext2_inode *inode, char *str, size_t len);
/* mode stuff */
#define S_IFMT 0170000
#define S_IFIFO 0010000
#define S_IFCHR 0020000
#define S_IFDIR 0040000
#define S_IFBLK 0060000
#define S_IFREG 0100000
#define S_IFLNK 0120000
#define S_IFSOCK 0140000
#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#endif

886
lk/lib/fs/ext2/ext3_fs.h Normal file
View File

@ -0,0 +1,886 @@
/*
* linux/include/linux/ext3_fs.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie (Paris VI)
*
* from
*
* linux/include/linux/minix_fs.h
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#ifndef _LINUX_EXT3_FS_H
#define _LINUX_EXT3_FS_H
#include <linux/types.h>
#include <linux/magic.h>
/*
* The second extended filesystem constants/structures
*/
/*
* Define EXT3FS_DEBUG to produce debug messages
*/
#undef EXT3FS_DEBUG
/*
* Define EXT3_RESERVATION to reserve data blocks for expanding files
*/
#define EXT3_DEFAULT_RESERVE_BLOCKS 8
/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
#define EXT3_MAX_RESERVE_BLOCKS 1027
#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0
/*
* Always enable hashed directories
*/
#define CONFIG_EXT3_INDEX
/*
* Debug code
*/
#ifdef EXT3FS_DEBUG
#define ext3_debug(f, a...) \
do { \
printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:", \
__FILE__, __LINE__, __FUNCTION__); \
printk (KERN_DEBUG f, ## a); \
} while (0)
#else
#define ext3_debug(f, a...) do {} while (0)
#endif
/*
* Special inodes numbers
*/
#define EXT3_BAD_INO 1 /* Bad blocks inode */
#define EXT3_ROOT_INO 2 /* Root inode */
#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */
#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */
#define EXT3_JOURNAL_INO 8 /* Journal inode */
/* First non-reserved inode for old ext3 filesystems */
#define EXT3_GOOD_OLD_FIRST_INO 11
/*
* Maximal count of links to a file
*/
#define EXT3_LINK_MAX 32000
/*
* Macro-instructions used to manage several block sizes
*/
#define EXT3_MIN_BLOCK_SIZE 1024
#define EXT3_MAX_BLOCK_SIZE 4096
#define EXT3_MIN_BLOCK_LOG_SIZE 10
#ifdef __KERNEL__
# define EXT3_BLOCK_SIZE(s) ((s)->s_blocksize)
#else
# define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
#endif
#define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32))
#ifdef __KERNEL__
# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
#else
# define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
#endif
#ifdef __KERNEL__
#define EXT3_ADDR_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_addr_per_block_bits)
#define EXT3_INODE_SIZE(s) (EXT3_SB(s)->s_inode_size)
#define EXT3_FIRST_INO(s) (EXT3_SB(s)->s_first_ino)
#else
#define EXT3_INODE_SIZE(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \
EXT3_GOOD_OLD_INODE_SIZE : \
(s)->s_inode_size)
#define EXT3_FIRST_INO(s) (((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \
EXT3_GOOD_OLD_FIRST_INO : \
(s)->s_first_ino)
#endif
/*
* Macro-instructions used to manage fragments
*/
#define EXT3_MIN_FRAG_SIZE 1024
#define EXT3_MAX_FRAG_SIZE 4096
#define EXT3_MIN_FRAG_LOG_SIZE 10
#ifdef __KERNEL__
# define EXT3_FRAG_SIZE(s) (EXT3_SB(s)->s_frag_size)
# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_SB(s)->s_frags_per_block)
#else
# define EXT3_FRAG_SIZE(s) (EXT3_MIN_FRAG_SIZE << (s)->s_log_frag_size)
# define EXT3_FRAGS_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s))
#endif
/*
* Structure of a blocks group descriptor
*/
struct ext3_group_desc
{
__le32 bg_block_bitmap; /* Blocks bitmap block */
__le32 bg_inode_bitmap; /* Inodes bitmap block */
__le32 bg_inode_table; /* Inodes table block */
__le16 bg_free_blocks_count; /* Free blocks count */
__le16 bg_free_inodes_count; /* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */
__u16 bg_pad;
__le32 bg_reserved[3];
};
/*
* Macro-instructions used to manage group descriptors
*/
#ifdef __KERNEL__
# define EXT3_BLOCKS_PER_GROUP(s) (EXT3_SB(s)->s_blocks_per_group)
# define EXT3_DESC_PER_BLOCK(s) (EXT3_SB(s)->s_desc_per_block)
# define EXT3_INODES_PER_GROUP(s) (EXT3_SB(s)->s_inodes_per_group)
# define EXT3_DESC_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_desc_per_block_bits)
#else
# define EXT3_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
# define EXT3_DESC_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_group_desc))
# define EXT3_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
#endif
/*
* Constants relative to the data blocks
*/
#define EXT3_NDIR_BLOCKS 12
#define EXT3_IND_BLOCK EXT3_NDIR_BLOCKS
#define EXT3_DIND_BLOCK (EXT3_IND_BLOCK + 1)
#define EXT3_TIND_BLOCK (EXT3_DIND_BLOCK + 1)
#define EXT3_N_BLOCKS (EXT3_TIND_BLOCK + 1)
/*
* Inode flags
*/
#define EXT3_SECRM_FL 0x00000001 /* Secure deletion */
#define EXT3_UNRM_FL 0x00000002 /* Undelete */
#define EXT3_COMPR_FL 0x00000004 /* Compress file */
#define EXT3_SYNC_FL 0x00000008 /* Synchronous updates */
#define EXT3_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT3_APPEND_FL 0x00000020 /* writes to file may only append */
#define EXT3_NODUMP_FL 0x00000040 /* do not dump file */
#define EXT3_NOATIME_FL 0x00000080 /* do not update atime */
/* Reserved for compression usage... */
#define EXT3_DIRTY_FL 0x00000100
#define EXT3_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
#define EXT3_NOCOMPR_FL 0x00000400 /* Don't compress */
#define EXT3_ECOMPR_FL 0x00000800 /* Compression error */
/* End compression flags --- maybe not all used */
#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */
#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */
#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
#define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */
#define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
#define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
#define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */
#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
/*
* Inode dynamic state flags
*/
#define EXT3_STATE_JDATA 0x00000001 /* journaled data exists */
#define EXT3_STATE_NEW 0x00000002 /* inode is newly created */
#define EXT3_STATE_XATTR 0x00000004 /* has in-inode xattrs */
/* Used to pass group descriptor data when online resize is done */
struct ext3_new_group_input {
__u32 group; /* Group number for this data */
__u32 block_bitmap; /* Absolute block number of block bitmap */
__u32 inode_bitmap; /* Absolute block number of inode bitmap */
__u32 inode_table; /* Absolute block number of inode table start */
__u32 blocks_count; /* Total number of blocks in this group */
__u16 reserved_blocks; /* Number of reserved blocks in this group */
__u16 unused;
};
/* The struct ext3_new_group_input in kernel space, with free_blocks_count */
struct ext3_new_group_data {
__u32 group;
__u32 block_bitmap;
__u32 inode_bitmap;
__u32 inode_table;
__u32 blocks_count;
__u16 reserved_blocks;
__u16 unused;
__u32 free_blocks_count;
};
/*
* ioctl commands
*/
#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS
#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS
#define EXT3_IOC_GETVERSION _IOR('f', 3, long)
#define EXT3_IOC_SETVERSION _IOW('f', 4, long)
#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input)
#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION
#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION
#ifdef CONFIG_JBD_DEBUG
#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
#endif
#define EXT3_IOC_GETRSVSZ _IOR('f', 5, long)
#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long)
/*
* ioctl commands in 32 bit emulation
*/
#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS
#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS
#define EXT3_IOC32_GETVERSION _IOR('f', 3, int)
#define EXT3_IOC32_SETVERSION _IOW('f', 4, int)
#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int)
#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int)
#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
#ifdef CONFIG_JBD_DEBUG
#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
#endif
#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
/*
* Mount options
*/
struct ext3_mount_options {
unsigned long s_mount_opt;
uid_t s_resuid;
gid_t s_resgid;
unsigned long s_commit_interval;
#ifdef CONFIG_QUOTA
int s_jquota_fmt;
char *s_qf_names[MAXQUOTAS];
#endif
};
/*
* Structure of an inode on the disk
*/
struct ext3_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks; /* Blocks count */
__le32 i_flags; /* File flags */
union {
struct {
__u32 l_i_reserved1;
} linux1;
struct {
__u32 h_i_translator;
} hurd1;
struct {
__u32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__le32 i_block[EXT3_N_BLOCKS];/* Pointers to blocks */
__le32 i_generation; /* File version (for NFS) */
__le32 i_file_acl; /* File ACL */
__le32 i_dir_acl; /* Directory ACL */
__le32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2 fields */
__le16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__u16 h_i_mode_high;
__u16 h_i_uid_high;
__u16 h_i_gid_high;
__u32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
__le16 i_extra_isize;
__le16 i_pad1;
};
#define i_size_high i_dir_acl
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
#define i_fsize osd2.linux2.l_i_fsize
#define i_uid_low i_uid
#define i_gid_low i_gid
#define i_uid_high osd2.linux2.l_i_uid_high
#define i_gid_high osd2.linux2.l_i_gid_high
#define i_reserved2 osd2.linux2.l_i_reserved2
#elif defined(__GNU__)
#define i_translator osd1.hurd1.h_i_translator
#define i_frag osd2.hurd2.h_i_frag;
#define i_fsize osd2.hurd2.h_i_fsize;
#define i_uid_high osd2.hurd2.h_i_uid_high
#define i_gid_high osd2.hurd2.h_i_gid_high
#define i_author osd2.hurd2.h_i_author
#elif defined(__masix__)
#define i_reserved1 osd1.masix1.m_i_reserved1
#define i_frag osd2.masix2.m_i_frag
#define i_fsize osd2.masix2.m_i_fsize
#define i_reserved2 osd2.masix2.m_i_reserved2
#endif /* defined(__KERNEL__) || defined(__linux__) */
/*
* File system states
*/
#define EXT3_VALID_FS 0x0001 /* Unmounted cleanly */
#define EXT3_ERROR_FS 0x0002 /* Errors detected */
#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */
/*
* Mount flags
*/
#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */
#define EXT3_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */
#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */
#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */
#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */
#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */
#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */
#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/
#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */
#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */
#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */
#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */
#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */
#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */
#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */
#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */
#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */
#define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
#define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
#define clear_opt(o, opt) o &= ~EXT3_MOUNT_##opt
#define set_opt(o, opt) o |= EXT3_MOUNT_##opt
#define test_opt(sb, opt) (EXT3_SB(sb)->s_mount_opt & \
EXT3_MOUNT_##opt)
#else
#define EXT2_MOUNT_NOLOAD EXT3_MOUNT_NOLOAD
#define EXT2_MOUNT_ABORT EXT3_MOUNT_ABORT
#define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS
#endif
#define ext3_set_bit ext2_set_bit
#define ext3_set_bit_atomic ext2_set_bit_atomic
#define ext3_clear_bit ext2_clear_bit
#define ext3_clear_bit_atomic ext2_clear_bit_atomic
#define ext3_test_bit ext2_test_bit
#define ext3_find_first_zero_bit ext2_find_first_zero_bit
#define ext3_find_next_zero_bit ext2_find_next_zero_bit
/*
* Maximal mount counts between two filesystem checks
*/
#define EXT3_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
#define EXT3_DFL_CHECKINTERVAL 0 /* Don't use interval check */
/*
* Behaviour when detecting errors
*/
#define EXT3_ERRORS_CONTINUE 1 /* Continue execution */
#define EXT3_ERRORS_RO 2 /* Remount fs read-only */
#define EXT3_ERRORS_PANIC 3 /* Panic */
#define EXT3_ERRORS_DEFAULT EXT3_ERRORS_CONTINUE
/*
* Structure of the super block
*/
struct ext3_super_block {
/*00*/ __le32 s_inodes_count; /* Inodes count */
__le32 s_blocks_count; /* Blocks count */
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count; /* Free blocks count */
/*10*/ __le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size; /* Fragment size */
/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group; /* # Inodes per group */
__le32 s_mtime; /* Mount time */
/*30*/ __le32 s_wtime; /* Write time */
__le16 s_mnt_count; /* Mount count */
__le16 s_max_mnt_count; /* Maximal mount count */
__le16 s_magic; /* Magic signature */
__le16 s_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */
__le16 s_minor_rev_level; /* minor revision level */
/*40*/ __le32 s_lastcheck; /* time of last check */
__le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */
__le32 s_rev_level; /* Revision level */
/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT3_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* size of inode structure */
__le16 s_block_group_nr; /* block group # of this superblock */
__le32 s_feature_compat; /* compatible feature set */
/*60*/ __le32 s_feature_incompat; /* incompatible feature set */
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
/*78*/ char s_volume_name[16]; /* volume name */
/*88*/ char s_last_mounted[64]; /* directory where last mounted */
/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
/*E0*/ __le32 s_journal_inum; /* inode number of journal file */
__le32 s_journal_dev; /* device number of journal file */
__le32 s_last_orphan; /* start of list of inodes to delete */
__le32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
};
#ifdef __KERNEL__
#include <linux/ext3_fs_i.h>
#include <linux/ext3_fs_sb.h>
static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
static inline struct ext3_inode_info *EXT3_I(struct inode *inode)
{
return container_of(inode, struct ext3_inode_info, vfs_inode);
}
static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino)
{
return ino == EXT3_ROOT_INO ||
ino == EXT3_JOURNAL_INO ||
ino == EXT3_RESIZE_INO ||
(ino >= EXT3_FIRST_INO(sb) &&
ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count));
}
#else
/* Assume that user mode programs are passing in an ext3fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
* macros from user land. */
#define EXT3_SB(sb) (sb)
#endif
#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime
/*
* Codes for operating systems
*/
#define EXT3_OS_LINUX 0
#define EXT3_OS_HURD 1
#define EXT3_OS_MASIX 2
#define EXT3_OS_FREEBSD 3
#define EXT3_OS_LITES 4
/*
* Revision levels
*/
#define EXT3_GOOD_OLD_REV 0 /* The good old (original) format */
#define EXT3_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
#define EXT3_CURRENT_REV EXT3_GOOD_OLD_REV
#define EXT3_MAX_SUPP_REV EXT3_DYNAMIC_REV
#define EXT3_GOOD_OLD_INODE_SIZE 128
/*
* Feature set definitions
*/
#define EXT3_HAS_COMPAT_FEATURE(sb,mask) \
( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask) \
( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask) \
( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
#define EXT3_SET_COMPAT_FEATURE(sb,mask) \
EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask) \
EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
#define EXT3_SET_INCOMPAT_FEATURE(sb,mask) \
EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask) \
EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask) \
EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
#define EXT3_FEATURE_COMPAT_DIR_PREALLOC 0x0001
#define EXT3_FEATURE_COMPAT_IMAGIC_INODES 0x0002
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
#define EXT3_FEATURE_COMPAT_EXT_ATTR 0x0008
#define EXT3_FEATURE_COMPAT_RESIZE_INODE 0x0010
#define EXT3_FEATURE_COMPAT_DIR_INDEX 0x0020
#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
#define EXT3_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010
#define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \
EXT3_FEATURE_INCOMPAT_RECOVER| \
EXT3_FEATURE_INCOMPAT_META_BG)
#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
/*
* Default values for user and/or group using reserved blocks
*/
#define EXT3_DEF_RESUID 0
#define EXT3_DEF_RESGID 0
/*
* Default mount options
*/
#define EXT3_DEFM_DEBUG 0x0001
#define EXT3_DEFM_BSDGROUPS 0x0002
#define EXT3_DEFM_XATTR_USER 0x0004
#define EXT3_DEFM_ACL 0x0008
#define EXT3_DEFM_UID16 0x0010
#define EXT3_DEFM_JMODE 0x0060
#define EXT3_DEFM_JMODE_DATA 0x0020
#define EXT3_DEFM_JMODE_ORDERED 0x0040
#define EXT3_DEFM_JMODE_WBACK 0x0060
/*
* Structure of a directory entry
*/
#define EXT3_NAME_LEN 255
struct ext3_dir_entry {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__le16 name_len; /* Name length */
char name[EXT3_NAME_LEN]; /* File name */
};
/*
* The new version of the directory entry. Since EXT3 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext3_dir_entry_2 {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT3_NAME_LEN]; /* File name */
};
/*
* Ext3 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT3_FT_UNKNOWN 0
#define EXT3_FT_REG_FILE 1
#define EXT3_FT_DIR 2
#define EXT3_FT_CHRDEV 3
#define EXT3_FT_BLKDEV 4
#define EXT3_FT_FIFO 5
#define EXT3_FT_SOCK 6
#define EXT3_FT_SYMLINK 7
#define EXT3_FT_MAX 8
/*
* EXT3_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
*/
#define EXT3_DIR_PAD 4
#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1)
#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \
~EXT3_DIR_ROUND)
/*
* Hash Tree Directory indexing
* (c) Daniel Phillips, 2001
*/
#ifdef CONFIG_EXT3_INDEX
#define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \
EXT3_FEATURE_COMPAT_DIR_INDEX) && \
(EXT3_I(dir)->i_flags & EXT3_INDEX_FL))
#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX)
#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
#else
#define is_dx(dir) 0
#define EXT3_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT3_LINK_MAX)
#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
#endif
/* Legal values for the dx_root hash_version field: */
#define DX_HASH_LEGACY 0
#define DX_HASH_HALF_MD4 1
#define DX_HASH_TEA 2
#ifdef __KERNEL__
/* hash info structure used by the directory hash */
struct dx_hash_info
{
u32 hash;
u32 minor_hash;
int hash_version;
u32 *seed;
};
#define EXT3_HTREE_EOF 0x7fffffff
/*
* Control parameters used by ext3_htree_next_block
*/
#define HASH_NB_ALWAYS 1
/*
* Describe an inode's exact location on disk and in memory
*/
struct ext3_iloc
{
struct buffer_head *bh;
unsigned long offset;
unsigned long block_group;
};
static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc)
{
return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset);
}
/*
* This structure is stuffed into the struct file's private_data field
* for directories. It is where we put information so that we can do
* readdir operations in hash tree order.
*/
struct dir_private_info {
struct rb_root root;
struct rb_node *curr_node;
struct fname *extra_fname;
loff_t last_pos;
__u32 curr_hash;
__u32 curr_minor_hash;
__u32 next_hash;
};
/* calculate the first block number of the group */
static inline ext3_fsblk_t
ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
{
return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
}
/*
* Special error return code only used by dx_probe() and its callers.
*/
#define ERR_BAD_DX_DIR -75000
/*
* Function prototypes
*/
/*
* Ok, these declarations are also in <linux/kernel.h> but none of the
* ext3 source programs needs to include it so they are duplicated here.
*/
# define NORET_TYPE /**/
# define ATTRIB_NORET __attribute__((noreturn))
# define NORET_AND noreturn,
/* balloc.c */
extern int ext3_bg_has_super(struct super_block *sb, int group);
extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode,
ext3_fsblk_t goal, int *errp);
extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode,
ext3_fsblk_t goal, unsigned long *count, int *errp);
extern void ext3_free_blocks (handle_t *handle, struct inode *inode,
ext3_fsblk_t block, unsigned long count);
extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb,
ext3_fsblk_t block, unsigned long count,
unsigned long *pdquot_freed_blocks);
extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *);
extern void ext3_check_blocks_bitmap (struct super_block *);
extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
unsigned int block_group,
struct buffer_head ** bh);
extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
extern void ext3_init_block_alloc_info(struct inode *);
extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv);
/* dir.c */
extern int ext3_check_dir_entry(const char *, struct inode *,
struct ext3_dir_entry_2 *,
struct buffer_head *, unsigned long);
extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
__u32 minor_hash,
struct ext3_dir_entry_2 *dirent);
extern void ext3_htree_free_dir_info(struct dir_private_info *p);
/* fsync.c */
extern int ext3_sync_file (struct file *, struct dentry *, int);
/* hash.c */
extern int ext3fs_dirhash(const char *name, int len, struct
dx_hash_info *hinfo);
/* ialloc.c */
extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
extern void ext3_free_inode (handle_t *, struct inode *);
extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
extern unsigned long ext3_count_free_inodes (struct super_block *);
extern unsigned long ext3_count_dirs (struct super_block *);
extern void ext3_check_inodes_bitmap (struct super_block *);
extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
/* inode.c */
int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
struct buffer_head *bh, ext3_fsblk_t blocknr);
struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
int ext3_get_blocks_handle(handle_t *handle, struct inode *inode,
sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
int create, int extend_disksize);
extern void ext3_read_inode (struct inode *);
extern int ext3_write_inode (struct inode *, int);
extern int ext3_setattr (struct dentry *, struct iattr *);
extern void ext3_delete_inode (struct inode *);
extern int ext3_sync_inode (handle_t *, struct inode *);
extern void ext3_discard_reservation (struct inode *);
extern void ext3_dirty_inode(struct inode *);
extern int ext3_change_inode_journal_flag(struct inode *, int);
extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
extern void ext3_truncate (struct inode *);
extern void ext3_set_inode_flags(struct inode *);
extern void ext3_get_inode_flags(struct ext3_inode_info *);
extern void ext3_set_aops(struct inode *inode);
/* ioctl.c */
extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
unsigned long);
extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long);
/* namei.c */
extern int ext3_orphan_add(handle_t *, struct inode *);
extern int ext3_orphan_del(handle_t *, struct inode *);
extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
__u32 start_minor_hash, __u32 *next_hash);
/* resize.c */
extern int ext3_group_add(struct super_block *sb,
struct ext3_new_group_data *input);
extern int ext3_group_extend(struct super_block *sb,
struct ext3_super_block *es,
ext3_fsblk_t n_blocks_count);
/* super.c */
extern void ext3_error (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
extern void __ext3_std_error (struct super_block *, const char *, int);
extern void ext3_abort (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
extern void ext3_warning (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
extern void ext3_update_dynamic_rev (struct super_block *sb);
#define ext3_std_error(sb, errno) \
do { \
if ((errno)) \
__ext3_std_error((sb), __FUNCTION__, (errno)); \
} while (0)
/*
* Inodes and files operations
*/
/* dir.c */
extern const struct file_operations ext3_dir_operations;
/* file.c */
extern const struct inode_operations ext3_file_inode_operations;
extern const struct file_operations ext3_file_operations;
/* namei.c */
extern const struct inode_operations ext3_dir_inode_operations;
extern const struct inode_operations ext3_special_inode_operations;
/* symlink.c */
extern const struct inode_operations ext3_symlink_inode_operations;
extern const struct inode_operations ext3_fast_symlink_inode_operations;
#endif /* __KERNEL__ */
#endif /* _LINUX_EXT3_FS_H */

145
lk/lib/fs/ext2/file.c Normal file
View File

@ -0,0 +1,145 @@
/*
* 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 <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <err.h>
#include <debug.h>
#include <lib/fs/ext2.h>
#include "ext2_priv.h"
#define LOCAL_TRACE 0
int ext2_open_file(fscookie cookie, const char *path, fsfilecookie *fcookie)
{
ext2_t *ext2 = (ext2_t *)cookie;
int err;
/* do a path lookup */
inodenum_t inum;
err = ext2_lookup(ext2, path, &inum);
if (err < 0)
return err;
/* create the file object */
ext2_file_t *file = malloc(sizeof(ext2_file_t));
memset(file, 0, sizeof(ext2_file_t));
/* read in the inode */
err = ext2_load_inode(ext2, inum, &file->inode);
if (err < 0) {
free(file);
return err;
}
file->ext2 = ext2;
*fcookie = file;
return 0;
}
int ext2_read_file(fsfilecookie fcookie, void *buf, off_t offset, size_t len)
{
ext2_file_t *file = (ext2_file_t *)fcookie;
int err;
// test that it's a file
if (!S_ISREG(file->inode.i_mode)) {
dprintf(INFO, "ext2_read_file: not a file\n");
return -1;
}
// read from the inode
err = ext2_read_inode(file->ext2, &file->inode, buf, offset, len);
return err;
}
int ext2_close_file(fsfilecookie fcookie)
{
ext2_file_t *file = (ext2_file_t *)fcookie;
// see if we need to free any of the cache blocks
int i;
for (i=0; i < 3; i++) {
if (file->ind_cache[i].num != 0) {
free(file->ind_cache[i].ptr);
}
}
free(file);
return 0;
}
off_t ext2_file_len(ext2_t *ext2, struct ext2_inode *inode)
{
/* calculate the file size */
off_t len = inode->i_size;
if ((ext2->sb.s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_LARGE_FILE) && (S_ISREG(inode->i_mode))) {
/* can potentially be a large file */
len |= (off_t)inode->i_size_high << 32;
}
return len;
}
int ext2_stat_file(fsfilecookie fcookie, struct file_stat *stat)
{
ext2_file_t *file = (ext2_file_t *)fcookie;
stat->size = ext2_file_len(file->ext2, &file->inode);
/* is it a dir? */
stat->is_dir = false;
if (S_ISDIR(file->inode.i_mode))
stat->is_dir = true;
return 0;
}
int ext2_read_link(ext2_t *ext2, struct ext2_inode *inode, char *str, size_t len)
{
LTRACEF("inode %p, str %p, len %d\n", inode, str, len);
off_t linklen = ext2_file_len(ext2, inode);
if ((linklen < 0) || (linklen + 1 > len))
return ERR_NO_MEMORY;
if (linklen > 60) {
int err = ext2_read_inode(ext2, inode, str, 0, linklen);
if (err < 0)
return err;
str[linklen] = 0;
} else {
memcpy(str, &inode->i_block[0], linklen);
str[linklen] = 0;
}
LTRACEF("read link '%s'\n", str);
return linklen;
}

269
lk/lib/fs/ext2/io.c Normal file
View File

@ -0,0 +1,269 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include <debug.h>
#include <lib/fs/ext2.h>
#include "ext2_priv.h"
#define LOCAL_TRACE 0
int ext2_read_block(ext2_t *ext2, void *buf, blocknum_t bnum)
{
return bcache_read_block(ext2->cache, buf, bnum);
}
int ext2_get_block(ext2_t *ext2, void **ptr, blocknum_t bnum)
{
return bcache_get_block(ext2->cache, ptr, bnum);
}
int ext2_put_block(ext2_t *ext2, blocknum_t bnum)
{
return bcache_put_block(ext2->cache, bnum);
}
static int ext2_calculate_block_pointer_pos(ext2_t *ext2, blocknum_t block_to_find, uint32_t *level, uint32_t pos[])
{
uint32_t block_ptr_per_block, block_ptr_per_2nd_block;
// XXX optimize this
// See if it's in the direct blocks
if(block_to_find < EXT2_NDIR_BLOCKS) {
*level = 0;
pos[0] = block_to_find;
return 0;
}
block_ptr_per_block = EXT2_ADDR_PER_BLOCK(ext2->sb);
block_to_find -= EXT2_NDIR_BLOCKS;
// See if it's in the first indirect block
if(block_to_find < block_ptr_per_block) {
*level = 1;
pos[0] = EXT2_IND_BLOCK;
pos[1] = block_to_find;
return 0;
}
block_to_find -= block_ptr_per_block;
block_ptr_per_2nd_block = block_ptr_per_block * block_ptr_per_block;
// See if it's in the second indirect block
if(block_to_find < (block_ptr_per_2nd_block)) {
*level = 2;
pos[0] = EXT2_DIND_BLOCK;
pos[1] = block_to_find / block_ptr_per_block;
pos[2] = block_to_find % block_ptr_per_block;
return 0;
}
block_to_find -= block_ptr_per_2nd_block;
// See if it's in the third indirect block
if(block_to_find < (block_ptr_per_2nd_block * block_ptr_per_block)) {
*level = 3;
pos[0] = EXT2_TIND_BLOCK;
pos[1] = block_to_find / block_ptr_per_2nd_block;
pos[2] = (block_to_find % block_ptr_per_2nd_block) / block_ptr_per_block;
pos[3] = (block_to_find % block_ptr_per_2nd_block) % block_ptr_per_block;
return 0;
}
// The block requested must be too big.
return -1;
}
// This function returns a pointer to the cache block that corresponds to the indirect block pointer.
int ext2_get_indirect_block_pointer_cache_block(ext2_t *ext2, struct ext2_inode *inode, blocknum_t **cache_block, uint32_t level, uint32_t pos[], uint *block_loaded)
{
uint32_t current_level = 0;
uint current_block = 0, last_block;
blocknum_t *block = NULL;
int err;
if ((level > 3) || (level == 0)) {
err = -1;
goto error;
}
// Dig down into the indirect blocks. When done, current_block should point to the target.
while (current_level < level) {
if (current_level == 0) {
// read the direct block, simulates a prior loop
current_block = LE32(inode->i_block[pos[0]]);
}
if (current_block == 0) {
err = -1;
goto error;
}
last_block = current_block;
current_level++;
*block_loaded = current_block;
err = ext2_get_block(ext2, (void **)(void *)&block, current_block);
if (err < 0) {
goto error;
}
if (current_level < level) {
current_block = LE32(block[pos[current_level]]);
ext2_put_block(ext2, last_block);
}
}
*cache_block = block;
return 0;
error:
*cache_block = NULL;
*block_loaded = 0;
return err;
}
/* translate a file block to a physical block */
static blocknum_t file_block_to_fs_block(ext2_t *ext2, struct ext2_inode *inode, uint fileblock)
{
int err;
blocknum_t block;
LTRACEF("inode %p, fileblock %u\n", inode, fileblock);
uint32_t pos[4];
uint32_t level = 0;
ext2_calculate_block_pointer_pos(ext2, fileblock, &level, pos);
LTRACEF("level %d, pos 0x%x 0x%x 0x%x 0x%x\n", level, pos[0], pos[1], pos[2], pos[3]);
if (level == 0) {
/* direct block, just return it directly */
block = LE32(inode->i_block[fileblock]);
} else {
/* at least one level of indirection, get a pointer to the final indirect block table and dereference it */
blocknum_t *ind_table;
blocknum_t phys_block;
err = ext2_get_indirect_block_pointer_cache_block(ext2, inode, &ind_table, level, pos, &phys_block);
if (err < 0)
return 0;
/* dereference the final entry in the final table */
block = LE32(ind_table[pos[level]]);
LTRACEF("block %u, indirect_block %u\n", block, phys_block);
/* release the ref on the cache block */
ext2_put_block(ext2, phys_block);
}
LTRACEF("returning %u\n", block);
return block;
}
int ext2_read_inode(ext2_t *ext2, struct ext2_inode *inode, void *_buf, off_t offset, size_t len)
{
int err = 0;
int bytes_read = 0;
uint8_t *buf = _buf;
/* calculate the file size */
off_t file_size = ext2_file_len(ext2, inode);
LTRACEF("inode %p, offset %lld, len %zd, file_size %lld\n", inode, offset, len, file_size);
/* trim the read */
if (offset > file_size)
return 0;
if (offset + len >= file_size)
len = file_size - offset;
if (len == 0)
return 0;
/* calculate the starting file block */
uint file_block = offset / EXT2_BLOCK_SIZE(ext2->sb);
/* handle partial first block */
if ((offset % EXT2_BLOCK_SIZE(ext2->sb)) != 0) {
uint8_t temp[EXT2_BLOCK_SIZE(ext2->sb)];
/* calculate the block and read it */
blocknum_t phys_block = file_block_to_fs_block(ext2, inode, file_block);
if (phys_block == 0) {
memset(temp, 0, EXT2_BLOCK_SIZE(ext2->sb));
} else {
ext2_read_block(ext2, temp, phys_block);
}
/* copy out what we need */
size_t block_offset = offset % EXT2_BLOCK_SIZE(ext2->sb);
size_t tocopy = MIN(len, EXT2_BLOCK_SIZE(ext2->sb) - block_offset);
memcpy(buf, temp + block_offset, tocopy);
/* increment our stuff */
file_block++;
len -= tocopy;
bytes_read += tocopy;
buf += tocopy;
}
/* handle middle blocks */
while (len >= EXT2_BLOCK_SIZE(ext2->sb)) {
/* calculate the block and read it */
blocknum_t phys_block = file_block_to_fs_block(ext2, inode, file_block);
if (phys_block == 0) {
memset(buf, 0, EXT2_BLOCK_SIZE(ext2->sb));
} else {
ext2_read_block(ext2, buf, phys_block);
}
/* increment our stuff */
file_block++;
len -= EXT2_BLOCK_SIZE(ext2->sb);
bytes_read += EXT2_BLOCK_SIZE(ext2->sb);
buf += EXT2_BLOCK_SIZE(ext2->sb);
}
/* handle partial last block */
if (len > 0) {
uint8_t temp[EXT2_BLOCK_SIZE(ext2->sb)];
/* calculate the block and read it */
blocknum_t phys_block = file_block_to_fs_block(ext2, inode, file_block);
if (phys_block == 0) {
memset(temp, 0, EXT2_BLOCK_SIZE(ext2->sb));
} else {
ext2_read_block(ext2, temp, phys_block);
}
/* copy out what we need */
memcpy(buf, temp, len);
/* increment our stuff */
bytes_read += len;
}
LTRACEF("err %d, bytes_read %d\n", err, bytes_read);
return (err < 0) ? err : bytes_read;
}

12
lk/lib/fs/ext2/rules.mk Normal file
View File

@ -0,0 +1,12 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += \
lib/fs \
lib/bcache \
lib/bio
OBJS += \
$(LOCAL_DIR)/ext2.o \
$(LOCAL_DIR)/dir.o \
$(LOCAL_DIR)/io.o \
$(LOCAL_DIR)/file.o

518
lk/lib/fs/fs.c Normal file
View File

@ -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;
}

9
lk/lib/fs/rules.mk Normal file
View File

@ -0,0 +1,9 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += \
# lib/fs/ext2
OBJS += \
$(LOCAL_DIR)/fs.o \
$(LOCAL_DIR)/debug.o

621
lk/lib/gfx/gfx.c Normal file
View File

@ -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 = &copyrect16;
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 = &copyrect32;
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

4
lk/lib/gfx/rules.mk Normal file
View File

@ -0,0 +1,4 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/gfx.o

View File

@ -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;
}

View File

@ -0,0 +1,7 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += lib/gfx \
lib/font
OBJS += \
$(LOCAL_DIR)/gfxconsole.o

View File

@ -30,6 +30,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'
@ -51,7 +57,7 @@ extern int _end_of_ram;
#define HEAP_LEN ((size_t)&_end_of_ram - (size_t)&_end)
#endif
struct free_heap_chunk {
struct __attribute__((__may_alias__)) free_heap_chunk {
struct list_node node;
size_t len;
};
@ -70,6 +76,10 @@ struct alloc_struct_begin {
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)
@ -202,7 +212,9 @@ try_merge:
struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len)
{
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,7 +224,9 @@ struct free_heap_chunk *heap_create_free_chunk(void *ptr, size_t len)
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);
// alignment must be power of 2
@ -221,6 +235,9 @@ void *heap_alloc(size_t size, unsigned int alignment)
// 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
@ -274,6 +291,10 @@ void *heap_alloc(size_t size, unsigned int alignment)
// the allocated size is actually the length of this chunk, not the size requested
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));
@ -287,6 +308,13 @@ void *heap_alloc(size_t size, unsigned int alignment)
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;
}
@ -313,6 +341,21 @@ void heap_free(void *ptr)
as--;
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);
@ -355,7 +398,7 @@ void heap_init(void)
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)

View File

@ -26,7 +26,6 @@
/* XXX unimplemented for now */
int iscntrl(int c);
int isgraph(int c);
int isprint(int c);
int ispunct(int c);
#endif
@ -70,6 +69,10 @@ int isxdigit(int c)
return isdigit(c) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
}
int isprint(int c)
{
return ((c >= 0x20) && (c < 0x7f));
}
int tolower(int c)
{
if ((c >= 'A') && (c <= 'Z'))

View File

@ -39,7 +39,7 @@ int puts(const char *str)
int getc(char *c)
{
return dgetc(c);
return dgetc(c, true);
}
int printf(const char *fmt, ...)

View File

@ -28,8 +28,7 @@
#include <string.h>
#include <sys/types.h>
void *
memset(void *s, int c, size_t count)
void *memset(void *s, int c, size_t count)
{
char *xs = (char *) s;
size_t len = (-(size_t)s) & (sizeof(size_t)-1);

View File

@ -28,6 +28,7 @@ C_STRING_OPS := \
strspn \
strstr \
strtok \
strtoul \
strxfrm
LIBC_STRING_C_DIR := $(LOCAL_DIR)

View File

@ -0,0 +1,174 @@
/*
* Copyright (C) 2011 Rick_1995@xda-developers.com
*
* Notes:
* The primary objective of this implementation was minimal size.
* Note: Assumes char layout 0-9.*A-Z.*a-z for ordinals values.
* There are a couple of compile-time options below.
*/
/*****************************************************************************/
/* OPTIONS */
/*****************************************************************************/
/* Set if we want strtod to set errno appropriately. */
/* NOTE: Implies _STRTO_ENDPTR below */
#define _STRTO_ERRNO 0
/* Set if we want support for the endptr arg. */
/* Implied by _STRTO_ERRNO. */
#define _STRTO_ENDPTR 1
/*****************************************************************************/
/* Don't change anything that follows. */
/*****************************************************************************/
#if _STRTO_ERRNO
#undef _STRTO_ENDPTR
#define _STRTO_ENDPTR 1
#endif
/*****************************************************************************/
/* Are there actually an machines where this might fail? */
#if 'A' > 'a'
#error ordering assumption violated : 'A' > 'a'
#endif
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#if _STRTO_ERRNO
#include <errno.h>
#endif
/*
* This is the main work fuction which handles both strtol (uflag = 0) and
* strtoul (uflag = 1).
*/
unsigned long _strto_l(const char *str, char **endptr, int base, int uflag)
{
unsigned long number = 0;
unsigned long cutoff;
char *pos = (char *) str;
#if _STRTO_ENDPTR
char *fail_char = (char *) str;
#endif
int digit, cutoff_digit;
int negative;
while (isspace(*pos)) { /* skip leading whitespace */
++pos;
}
/* handle optional sign */
negative = 0;
switch(*pos) {
case '-': negative = 1; /* fall through to increment pos */
case '+': ++pos;
}
if ((base == 16) && (*pos == '0')) { /* handle option prefix */
++pos;
#if _STRTO_ENDPTR
fail_char = pos;
#endif
if ((*pos == 'x') || (*pos == 'X')) {
++pos;
}
}
if (base == 0) { /* dynamic base */
base = 10; /* default is 10 */
if (*pos == '0') {
++pos;
base -= 2; /* now base is 8 (or 16) */
#if _STRTO_ENDPTR
fail_char = pos;
#endif
if ((*pos == 'x') || (*pos == 'X')) {
base += 8; /* base is 16 */
++pos;
}
}
}
if ((base < 2) || (base > 36)) { /* illegal base */
goto DONE;
}
cutoff = ULONG_MAX / base;
cutoff_digit = ULONG_MAX - cutoff * base;
while (1) {
digit = 40;
if ((*pos >= '0') && (*pos <= '9')) {
digit = (*pos - '0');
} else if (*pos >= 'a') {
digit = (*pos - 'a' + 10);
} else if (*pos >= 'A') {
digit = (*pos - 'A' + 10);
} else break;
if (digit >= base) {
break;
}
++pos;
#if _STRTO_ENDPTR
fail_char = pos;
#endif
/* adjust number, with overflow check */
if ((number > cutoff)
|| ((number == cutoff) && (digit > cutoff_digit))) {
number = ULONG_MAX;
if (uflag) {
negative = 0; /* since unsigned returns ULONG_MAX */
}
#if _STRTO_ERRNO
errno = ERANGE;
#endif
} else {
number = number * base + digit;
}
}
DONE:
#if _STRTO_ENDPTR
if (endptr) {
*endptr = fail_char;
}
#endif
if (negative) {
if (!uflag && (number > ((unsigned long)(-(1+LONG_MIN)))+1)) {
#if _STRTO_ERRNO
errno = ERANGE;
#endif
return (unsigned long) LONG_MIN;
}
return (unsigned long)(-((long)number));
} else {
if (!uflag && (number > (unsigned long) LONG_MAX)) {
#if _STRTO_ERRNO
errno = ERANGE;
#endif
return LONG_MAX;
}
return number;
}
}
unsigned long strtoul(const char *str, char **endptr, int base)
{
return _strto_l(str, endptr, base, 1);
}
long strtol(const char *str, char **endptr, int base)
{
return _strto_l(str, endptr, base, 0);
}

View File

@ -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;
}

View File

@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += lib/bio
OBJS += \
$(LOCAL_DIR)/partition.o

View File

@ -36,7 +36,6 @@
void ptable_init(struct ptable *ptable)
{
ASSERT(ptable);
memset(ptable, 0, sizeof(struct ptable));
}
@ -66,10 +65,12 @@ void ptable_dump(struct ptable *ptable)
for (i = 0; i < ptable->count; ++i) {
ptn = &ptable->parts[i];
dprintf(INFO, "ptn %d name='%s' start=%08x len=%08x "
//Fix it lateron. Ptable dumping not so important for now -.-
/*dprintf(INFO, "ptn %d name='%s' start=%08x len=%08x "
"flags=%08x type=%s Writable=%s\n", i, ptn->name, ptn->start, ptn->length,
ptn->flags, ptype[ptn->type], pperm[ptn->perm]);
}
ptn->flags, ptype[ptn->type], pperm[ptn->perm]);*/
}
}
struct ptentry *ptable_find(struct ptable *ptable, const char *name)

6
lk/lib/text/rules.mk Normal file
View File

@ -0,0 +1,6 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULES += lib/font
OBJS += \
$(LOCAL_DIR)/text.o

99
lk/lib/text/text.c Normal file
View File

@ -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);
}

4
lk/lib/tga/rules.mk Normal file
View File

@ -0,0 +1,4 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/tga.o

230
lk/lib/tga/tga.c Normal file
View File

@ -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;
}

4
lk/lib/vptable/rules.mk Normal file
View File

@ -0,0 +1,4 @@
LOCAL_DIR := $(GET_LOCAL_DIR)
OBJS += \
$(LOCAL_DIR)/vptable.o

404
lk/lib/vptable/vptable.c Normal file
View File

@ -0,0 +1,404 @@
/*
Simple routines for reading and writing partition table
Copyright (c) 2011 - Danijel Posilovic - dan1j3l
*/
#include <debug.h>
#include <arch/arm.h>
#include <dev/udc.h>
#include <string.h>
#include <kernel/thread.h>
#include <arch/ops.h>
#include <dev/flash.h>
#include <lib/ptable.h>
#include <dev/keys.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lib/vptable.h>
static const int MISC_PAGES = 3;
static const int MISC_COMMAND_PAGE = 0;
static char buf[4096];
extern struct ptable *flash_get_vptable(void);
int read_vptable(struct vpartitions *out){
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
unsigned pagesize = flash_page_size();
ptable = flash_get_vptable();
if (ptable == NULL) {
dprintf(CRITICAL, "ERROR: VPTABLE not found!!!\n");
return -1;
}
ptn = ptable_find(ptable, "vptable");
if (ptn == NULL) {
dprintf(CRITICAL, "ERROR: No vptable partition!!!\n");
return -1;
}
offset += (pagesize * MISC_COMMAND_PAGE);
if (flash_read(ptn, offset, buf, pagesize)) {
//dprintf(CRITICAL, "ERROR: Cannot read vpt header\n");
//return -1;
}
memcpy(out, buf, sizeof(*out));
return 0;
}
int write_vptable(const struct vpartitions *in){
struct ptentry *ptn;
struct ptable *ptable;
unsigned offset = 0;
unsigned pagesize = flash_page_size();
unsigned n = 0;
ptable = flash_get_vptable();
if (ptable == NULL) {
printf(CRITICAL, "ERROR: VPTABLE table not found!!!\n");
return -1;
}
ptn = ptable_find(ptable, "vptable");
if (ptn == NULL) {
printf(CRITICAL, "ERROR: No vptable partition!!!\n");
return -1;
}
n = pagesize * (MISC_COMMAND_PAGE + 1);
//if (flash_read(ptn, offset, SCRATCH_ADDR, n)) {
// printf(CRITICAL, "ERROR: Cannot read vpt header\n");
// return -1;
//}
offset += (pagesize * MISC_COMMAND_PAGE);
offset += SCRATCH_ADDR;
memcpy((void *)offset, in, sizeof(*in));
if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
printf(CRITICAL, "ERROR: flash write fail!\n");
return -1;
}
return 0;
}
unsigned vpart_available_size(){
unsigned used =0;
for (unsigned i=0;;i++){
if ((strlen(vparts.pdef[i].name) != 0) && (vparts.pdef[i].asize == 0)){
used += vparts.pdef[i].size;
} else {
break;
}
}
return (flash_size_blk - used);
}
bool vpart_variable_exist(){
for (unsigned i=0;i < (unsigned)MAX_NUM_PART;i++){
if ((strlen(vparts.pdef[i].name) != 0) && (vparts.pdef[i].asize == 1)) return 1;
}
return 0;
}
bool vpart_partition_exist(const char* pName){
for (unsigned i=0;i < (unsigned)MAX_NUM_PART;i++){
if (!memcmp(vparts.pdef[i].name,pName,strlen(pName)))return 1;
}
return 0;
}
void vpart_resize_asize(){
for (unsigned i=0; i < (unsigned)MAX_NUM_PART;i++){
if ((strlen(vparts.pdef[i].name) != 0) && (vparts.pdef[i].asize == 1)){
vparts.pdef[i].size = vpart_available_size();
return;
}
}
}
extern int atoi ( const char * str );
void vpart_add(const char *pData){
char buff[64];
char name[32];
char* tmp_buff;
unsigned size;
strcpy(buff,pData);
tmp_buff = strtok(buff,":");
strcpy(name,tmp_buff);
tmp_buff=strtok(NULL,":");
size = atoi(tmp_buff)*blk_pmb;
if (strlen(name)==0){
//fastboot_fail("Undefined partition name ! usage: fastboot oem part-add name:size");
return;
}
if (size==0 && vpart_available_size()<8){
//fastboot_fail("No available space for variable partition!");
return;
}
if (size==0 && vpart_variable_exist()){
//fastboot_fail("Autosize partition already exist!");
return;
}
if (vpart_partition_exist(name)){
//fastboot_fail("Named partition already exist!");
return;
}
for (unsigned i=0; i< (unsigned)MAX_NUM_PART; i++){
if (strlen(vparts.pdef[i].name) == 0){
strcpy(vparts.pdef[i].name,name);
if (size==0){
vparts.pdef[i].size=vpart_available_size();
vparts.pdef[i].asize=1;
}else{
vparts.pdef[i].size = size;
vparts.pdef[i].asize=0;
}
vpart_resize_asize();
break;
}
}
}
extern int atoi ( const char * str );
void vpart_resize(const char *pData){
char buff[64];
char name[32];
char* tmp_buff;
unsigned size;
unsigned old_size=0;
unsigned tmp_available_size=0;
strcpy(buff,pData);
tmp_buff = strtok(buff,":");
strcpy(name,tmp_buff);
tmp_buff=strtok(NULL,":");
size = atoi(tmp_buff)*blk_pmb;
if (strlen(name)==0){
//fastboot_fail("Undefined partition size!");
return;
}
for (unsigned i=0; i < (unsigned)MAX_NUM_PART;i++){
if ((strlen(vparts.pdef[i].name) != 0) && (!memcmp(vparts.pdef[i].name,name,strlen(name))) && (vparts.pdef[i].asize == 0) ){
old_size = vparts.pdef[i].size;
}
}
tmp_available_size = vpart_available_size() + old_size;
if (size>tmp_available_size)
size=tmp_available_size;
if (size==0 && tmp_available_size<8){
//fastboot_fail("No more space for variable partition!");
return;
}
if (size==0 && vpart_variable_exist()){
//fastboot_fail("Unable to set to autosize, autosize partition already exist!");
return;
}
for (unsigned i=0;i<(unsigned)MAX_NUM_PART;i++){
if (!memcmp(vparts.pdef[i].name,name,strlen(name))){
if (size==0){
vparts.pdef[i].size=tmp_available_size;
vparts.pdef[i].asize=1;
}else{
vparts.pdef[i].size = size;
vparts.pdef[i].asize=0;
}
vpart_resize_asize();
break;
}
}
}
// Restruct ptable and remove empty space between partitions
void vpart_restruct(){
for (unsigned i=0;i < (unsigned)MAX_NUM_PART;i++){
if (strlen(vparts.pdef[i].name)==0){
for (unsigned j=i; j < (unsigned)MAX_NUM_PART;j++){
if (strlen(vparts.pdef[j].name) != 0){
// Copy values to empty space
strcpy(vparts.pdef[i].name,vparts.pdef[j].name);
vparts.pdef[i].size=vparts.pdef[j].size;
vparts.pdef[i].asize=vparts.pdef[j].asize;
// Mark old values dirty
strcpy(vparts.pdef[j].name,"");
vparts.pdef[j].size=0;
vparts.pdef[j].asize=0;
break;
}
}
}
}
}
// Remove partition from ptable
void vpart_del(const char *pName){
for (unsigned i=0;i < (unsigned)MAX_NUM_PART;i++){
if (!memcmp(vparts.pdef[i].name,pName,strlen(pName))){
strcpy(vparts.pdef[i].name,"");
vparts.pdef[i].size=0;
vparts.pdef[i].asize=0;
vpart_restruct();
vpart_resize_asize();
}
}
}
// clear curent layout
void vpart_clear(){
strcpy(vparts.tag,"");
for (unsigned i=0;i < (unsigned)MAX_NUM_PART;i++){
strcpy(vparts.pdef[i].name,"");
vparts.pdef[i].size=0;
vparts.pdef[i].asize=0;
}
}
// Print current ptable
void vpart_list(){
printf("\n\n============================== PARTITION TABLE ==============================\n\n");
for (unsigned i=0;;i++){
if (strlen(vparts.pdef[i].name) != 0){
printf("%i.",i+1);
//fbcon_move_right(4);
printf("%s", vparts.pdef[i].name);
//fbcon_move_right(25);
printf( "| blocks: %i",vparts.pdef[i].size);
//fbcon_move_right(50);
printf( "| size: %i Mb\n",(vparts.pdef[i].size/blk_pmb));
} else {
break;
}
}
printf("\n\n============================== PARTITION TABLE ==============================\n\n");
}
// Create default partition layout
void vpart_create_default(){
vpart_clear();
vpart_add("misc:1");
vpart_add("recovery:5");
vpart_add("boot:5");
vpart_add("system:150");
vpart_add("cache:5");
vpart_add("userdata:0");
}
void vpart_commit(){
strcpy(vparts.tag,"VPTABLE");
write_vptable(&vparts);
}
void vpart_read(){
vpart_clear();
read_vptable(&vparts);
}
void vpart_enable_extrom(){
vparts.extrom_enabled = 1;
vpart_commit();
//cprint(cRed,cWhite,"ExtROM Enabled ! \n Reboot your phone and repartition nand to use ExtROM !!!\n\n");
}
void vpart_disable_extrom(){
vparts.extrom_enabled = 0;
vpart_commit();
//cprint(cRed,cWhite,"ExtROM Disabled ! \n Reboot your phone and repartition nand to remove ExtROM !!!\n\n");
}
// Init and load ptable from nand
void init_vpart(){
vpart_read();
if (memcmp(vparts.tag,"VPTABLE",7)){ // Bad mojo ! ptable does not exist, lets create default one !!!
vparts.extrom_enabled = 0;
flash_size_blk = flash_size_blk - 191; // extrom size
vpart_create_default();
vpart_commit();
}
if (vparts.extrom_enabled==0)
flash_size_blk = flash_size_blk - 191; // extrom size
}

View File

@ -149,7 +149,7 @@ clean: $(EXTRA_CLEANDEPS)
spotless:
rm -rf build-*
install: all
scp $(OUTBIN) 192.168.0.4:/tftproot

View File

@ -55,7 +55,7 @@ void _dputc(char c)
#endif
}
int dgetc(char *c)
int dgetc(char *c, bool wait)
{
int n;
#if WITH_DEBUG_DCC

View File

@ -31,11 +31,14 @@
#include <string.h>
#include <stdlib.h>
#include <debug.h>
#include <reg.h>
#include <platform/iomap.h>
#include <platform/irqs.h>
#include <platform/interrupts.h>
#include <platform/timer.h>
#include <kernel/thread.h>
#include <reg.h>
#include <dev/udc.h>
@ -46,6 +49,11 @@ int charger_usb_i(unsigned current);
int charger_usb_is_pc_connected(void);
int charger_usb_is_charger_connected(void);
static unsigned WALL_CHARGER = FALSE;
static unsigned HOST_CHARGER = FALSE;
static unsigned ENABLE_CHARGING = TRUE;
static unsigned charger_connected = FALSE;
/* common code - factor out into a shared file */
struct udc_descriptor {
@ -113,10 +121,7 @@ unsigned udc_string_desc_alloc(const char *str)
/* end of common code */
__WEAK void hsusb_clock_init(void)
{
return 0;
}
__WEAK void hsusb_clock_init(void){}
#if 1
#define DBG(x...) do {} while(0)
@ -531,7 +536,7 @@ int udc_init(struct udc_device *dev)
epts = memalign(4096, 4096);
dprintf(INFO, "USB init ept @ %p\n", epts);
//dprintf(INFO, "USB init ept @ %p\n", epts);
memset(epts, 0, 32 * sizeof(struct ept_queue_head));
//dprintf(INFO, "USB ID %08x\n", readl(USB_ID));
@ -594,7 +599,7 @@ enum handler_return udc_interrupt(void *arg)
writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT);
writel(0xffffffff, USB_ENDPTFLUSH);
writel(0, USB_ENDPTCTRL(1));
DBG1("-- reset --\n");
//DBG1("-- reset --\n");
usb_online = 0;
usb_config_value = 0;
the_gadget->notify(the_gadget, UDC_EVENT_OFFLINE);
@ -612,7 +617,7 @@ enum handler_return udc_interrupt(void *arg)
usb_status(0, usb_highspeed);
}
if (n & STS_SLI) {
DBG1("-- suspend --\n");
//DBG1("-- suspend --\n");
#ifdef ENABLE_BATTERY_CHARGING
if(HOST_CHARGER == TRUE){
charger_usb_i(2);
@ -620,7 +625,7 @@ enum handler_return udc_interrupt(void *arg)
#endif
}
if (n & STS_PCI) {
DBG1("-- portchange --\n");
//DBG1("-- portchange --\n");
unsigned spd = (readl(USB_PORTSC) >> 26) & 3;
if(spd == 2) {
usb_highspeed = 1;
@ -723,7 +728,7 @@ int udc_start(void)
unsigned char *data;
unsigned size;
dprintf(ALWAYS, "udc_start()\n");
//dprintf(ALWAYS, "udc_start()\n");
if (!the_device) {
dprintf(CRITICAL, "udc cannot start before init\n");
@ -777,7 +782,6 @@ int udc_start(void)
int udc_stop(void)
{
int val;
writel(0, USB_USBINTR);
mask_interrupt(INT_USB_HS);
@ -790,7 +794,6 @@ int udc_stop(void)
writel(val, 0x009034C0);
#endif
thread_sleep(10);
return 0;
}

View File

@ -175,10 +175,6 @@ struct ept_queue_item
#define PORTSC_LS (3 << 10) /* Read - Port's Line status */
#define B_SESSION_VALID (1 << 11)
static unsigned WALL_CHARGER = FALSE;
static unsigned HOST_CHARGER = FALSE;
static unsigned ENABLE_CHARGING = TRUE;
static unsigned charger_connected = FALSE;
enum charger_type {
CHG_HOST_PC,
@ -186,4 +182,6 @@ enum charger_type {
CHG_UNDEFINED,
};
int usb_cable_status(void);
#endif

View File

@ -591,6 +591,9 @@ struct mbr_entry
#define MMC_BOOT_WR_BLOCK_LEN 512
/* We have 16 32-bits FIFO registers */
#ifdef MMC_BOOT_MCI_FIFO_COUNT
#undef MMC_BOOT_MCI_FIFO_COUNT
#endif
#define MMC_BOOT_MCI_FIFO_COUNT 16
#define MMC_BOOT_MCI_HFIFO_COUNT ( MMC_BOOT_MCI_FIFO_COUNT / 2 )
#define MMC_BOOT_MCI_FIFO_SIZE ( MMC_BOOT_MCI_FIFO_COUNT * 4 )

Some files were not shown because too many files have changed in this diff Show More