Compare commits
53 Commits
f5dae4984d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a52dc89f9f | |||
| cc2b96f37a | |||
| 80a29d8ff6 | |||
| 4f55d765b4 | |||
| ec732d4627 | |||
| 3f3795df3c | |||
| 2faad79559 | |||
| 9b25dcd691 | |||
| 33b3a641fb | |||
| d3a91b6438 | |||
| fa152cac4d | |||
| e105b2fe35 | |||
| 7f78f20b17 | |||
| b4d6315dea | |||
| a05e73e69a | |||
| 0cc78a7247 | |||
| 5d77974586 | |||
| ae6f5d9df0 | |||
| ecfe1a7eae | |||
| 88f9d0e3d4 | |||
| 28c95303e9 | |||
| 638214a0e2 | |||
| 4fb5448dd9 | |||
| 2a0dddead3 | |||
| edcdaa5c60 | |||
| 77b5a4a153 | |||
| f2b7c5da57 | |||
| 58a47edc79 | |||
| 0a43ba36cd | |||
| e66fe4030d | |||
| 55b58bbe22 | |||
| bc53f9746e | |||
| d7059ac4e3 | |||
| af27592957 | |||
| 7da422fdb6 | |||
| 871c9cf439 | |||
| cf4a6b23c7 | |||
| 71fa87d7a4 | |||
| ecee481b33 | |||
| 3726cc49da | |||
| ef7a45e7cf | |||
| a530304e18 | |||
| f8863d19bd | |||
| f9d3fde4ad | |||
| c2364fbd48 | |||
| 4fe907a733 | |||
| 07fc8a5562 | |||
| 5bd6ca0fa7 | |||
| 7256fcd818 | |||
| 51e89c8603 | |||
| 566b35f4d5 | |||
| 7015bc9576 | |||
| 344952fb5f |
@ -1,3 +1,7 @@
|
||||
print 'Mounting filesystems...\n'
|
||||
setlogcmds yes
|
||||
$fs mount -mp uhome -fs LittleFS -dev atasd-ch0-M-part2 -fmt no
|
||||
|
||||
# MOUNTPOINT FILESYSTEM DEVICE NAME DO FORMATTING
|
||||
|
||||
$fs mount -mp uhome -fs LittleFS -dev atasd0mp2 -fmt no
|
||||
$fs mount -mp sys -fs FAT16 -dev atasd0mp1 -fmt no
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
# Create an $alias out of basenames of each entry in base:/bin
|
||||
eachfile !.gitkeep base:/bin \
|
||||
mkaliasbn &EF-ELEM
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "hal/hal.h"
|
||||
#include "fastlz.h"
|
||||
#include "FastLZ/fastlz.h"
|
||||
#include "std/string.h"
|
||||
|
||||
#define SIXPACK_OK 0
|
||||
#define SIXPACK_ERR_MAGIC -1
|
||||
@ -93,7 +93,7 @@ int sixpack_decompress_mem(const uint8_t *input, size_t in_size,
|
||||
/* Stored (uncompressed) */
|
||||
if (written + size > out_cap)
|
||||
return SIXPACK_ERR_NO_SPACE;
|
||||
hal_memcpy(output + written, chunk_data, size);
|
||||
memcpy(output + written, chunk_data, size);
|
||||
written += size;
|
||||
} else if (opts == 1) {
|
||||
/* FastLZ compressed */
|
||||
|
||||
@ -4,7 +4,8 @@ include $(ROOT)/mk/grabsrc.mk
|
||||
|
||||
PUTCHAR_ ?= fb
|
||||
|
||||
CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc
|
||||
CFLAGS := -ffreestanding -Wall -Wextra -fcommon -nostdinc \
|
||||
-fdata-sections -ffunction-sections
|
||||
|
||||
CFLAGS += -I. \
|
||||
-I$(ROOT)/limine \
|
||||
@ -21,11 +22,13 @@ CFLAGS += -I. \
|
||||
-DLFS_NO_WARN \
|
||||
-DLFS_NO_ERROR \
|
||||
-DFASTLZ_USE_MEMMOVE=0 \
|
||||
-DFATFS_MAX_OPEN_FILES=128 \
|
||||
-D"FAT_PRINTF(a)"
|
||||
|
||||
include arch/$(ARCH)/$(ARCH).mk
|
||||
include extconf/extra.mk
|
||||
|
||||
LDFLAGS += -nostdlib -static -T arch/$(ARCH)/link.ld $(shell $(CC) -print-libgcc-file-name)
|
||||
LDFLAGS += -nostdlib -static -T arch/$(ARCH)/link.ld $(shell $(CC) -print-libgcc-file-name) \
|
||||
--gc-sections --strip-all
|
||||
|
||||
SRCFILES :=
|
||||
|
||||
@ -44,10 +47,10 @@ SRCFILES += $(call GRABSRC, \
|
||||
fs/kvfs \
|
||||
fs/littlefs \
|
||||
fs/portlfs \
|
||||
fs/fatfs \
|
||||
fs/portfatfs \
|
||||
baseimg \
|
||||
proc \
|
||||
hal \
|
||||
hal/$(ARCH) \
|
||||
std \
|
||||
flanterm/src \
|
||||
flanterm/src/flanterm_backends \
|
||||
@ -55,11 +58,20 @@ SRCFILES += $(call GRABSRC, \
|
||||
path \
|
||||
rbuf \
|
||||
ipc/pipe \
|
||||
ipc/mbus \
|
||||
dev \
|
||||
randcrypto \
|
||||
time \
|
||||
diskpart \
|
||||
FastLZ \
|
||||
io \
|
||||
intr \
|
||||
cpu \
|
||||
vmm \
|
||||
pci \
|
||||
pci/ata \
|
||||
pci/qemu_pci_serial \
|
||||
cjob \
|
||||
)
|
||||
|
||||
CFILES := $(call GET_CFILES, $(SRCFILES))
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
#ifndef ASSERT_H_
|
||||
#define ASSERT_H_
|
||||
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
|
||||
#define ASSERT(mod, cond, fmt, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
ERR(mod, fmt, ##__VA_ARGS__); \
|
||||
hal_hang(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif // ASSERT_H_
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef ATOMIC_H_
|
||||
#define ATOMIC_H_
|
||||
|
||||
#define ATOMIC(X) _Atomic(X)
|
||||
|
||||
#endif // ATOMIC_H_
|
||||
@ -1,14 +1,15 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <limine.h>
|
||||
#include "baseimg.h"
|
||||
#include "baseimg/baseimg.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "kprintf.h"
|
||||
#include "util/util.h"
|
||||
#include "hal/hal.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "FastLZ/fastlz.h"
|
||||
#include "FastLZ/6unpack_mem.h"
|
||||
#include "std/string.h"
|
||||
#include "cpu/hang.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
#define BASEIMG_DECOMPRESSED (1024*1024*4)
|
||||
|
||||
@ -29,7 +30,7 @@ void baseimg_init(void) {
|
||||
LOG("baseimg", "looking for base image...\n");
|
||||
for (size_t i = 0; i < BOOT_INFO.modules->module_count; i++) {
|
||||
struct limine_file *module = BOOT_INFO.modules->modules[i];
|
||||
if (hal_strcmp(util_get_filename(module->path), "base.img.6pk") == 0) {
|
||||
if (strcmp(util_get_filename(module->path), "base.img.6pk") == 0) {
|
||||
baseimg = module;
|
||||
break;
|
||||
}
|
||||
@ -37,7 +38,7 @@ void baseimg_init(void) {
|
||||
|
||||
if (baseimg == NULL) {
|
||||
ERR("baseimg", "base.img.6pk not found\n");
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
} else {
|
||||
LOG("baseimg", "base.img.6pk found\n");
|
||||
LOG("baseimg", "addr = %p, size = %lu\n", baseimg->address, baseimg->size);
|
||||
@ -54,7 +55,7 @@ void baseimg_init(void) {
|
||||
BASEIMG_DECOMP_ADDR, BASEIMG_DECOMPRESSED);
|
||||
if (res < 0) {
|
||||
ERR("baseimg", "could not uncompress base.img.6pk\n");
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
BASEIMG_DECOMP_SIZE = res;
|
||||
kprintf("%p %zu\n", BASEIMG_DECOMP_ADDR, BASEIMG_DECOMP_SIZE);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "bitmap.h"
|
||||
#include "bitmap/bitmap.h"
|
||||
#include "util/util.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
|
||||
@ -4,8 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "hal/hal.h"
|
||||
#include "vmm/vmm.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t *map;
|
||||
@ -17,7 +16,7 @@ typedef struct {
|
||||
} BitMap;
|
||||
|
||||
#define BITMAP_BLOCKS_PER_BYTE 8
|
||||
#define BITMAP_BLOCK_SIZE HAL_PAGE_SIZE
|
||||
#define BITMAP_BLOCK_SIZE VMM_PAGE_SIZE
|
||||
#define BITMAP_INVALID_BLOCK ((size_t)-1)
|
||||
|
||||
void *bitmap_toptr(BitMap *bm, size_t block);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <limine.h>
|
||||
#include "bootinfo.h"
|
||||
#include "hal/hal.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "cpu/hang.h"
|
||||
|
||||
BootInfo BOOT_INFO;
|
||||
|
||||
@ -26,7 +26,7 @@ DEFINE_REQ(module, MODULE);
|
||||
|
||||
void bootinfo_init(void) {
|
||||
if (framebuffer_req.response == NULL || framebuffer_req.response->framebuffer_count < 1) {
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
BOOT_INFO.fb = framebuffer_req.response->framebuffers[0];
|
||||
|
||||
@ -35,7 +35,7 @@ void bootinfo_init(void) {
|
||||
|
||||
struct limine_paging_mode_response *pagingres = paging_req.response;
|
||||
if (pagingres->mode != LIMINE_PAGING_MODE_X86_64_4LVL) {
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
|
||||
struct limine_hhdm_response *hhdmres = hhdm_req.response;
|
||||
@ -68,7 +68,7 @@ void bootinfo_init(void) {
|
||||
}
|
||||
}
|
||||
if (BOOT_INFO.smp_bspindex == (uint64_t)-1) {
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
|
||||
struct limine_rsdp_response *rsdpres = rsdp_req.response;
|
||||
|
||||
36
kernel/cjob/cjob.c
Normal file
36
kernel/cjob/cjob.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "cjob/cjob.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "util/util.h"
|
||||
|
||||
CJobs CJOBS;
|
||||
static uint64_t cjobids = 0;
|
||||
|
||||
void cjob_init(void) {
|
||||
spinlock_init(&CJOBS.spinlock);
|
||||
CJOBS.cjobs = NULL;
|
||||
}
|
||||
|
||||
int32_t cjob_register(CJobFn fn, void *arg) {
|
||||
CJob *cjob = dlmalloc(sizeof(*cjob));
|
||||
cjob->fn = fn;
|
||||
cjob->arg = arg;
|
||||
int32_t id = cjob->id = cjobids++;
|
||||
|
||||
spinlock_acquire(&CJOBS.spinlock);
|
||||
LL_APPEND(CJOBS.cjobs, cjob);
|
||||
spinlock_release(&CJOBS.spinlock);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void cjob_runjobs(void) {
|
||||
CJob *cjob, *cjobtmp;
|
||||
spinlock_acquire(&CJOBS.spinlock);
|
||||
LL_FOREACH_SAFE(CJOBS.cjobs, cjob, cjobtmp) {
|
||||
cjob->fn(cjob->arg);
|
||||
}
|
||||
spinlock_release(&CJOBS.spinlock);
|
||||
}
|
||||
29
kernel/cjob/cjob.h
Normal file
29
kernel/cjob/cjob.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef CJOB_CJOB_H_
|
||||
#define CJOB_CJOB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "spinlock/spinlock.h"
|
||||
|
||||
typedef void (*CJobFn)(void *arg);
|
||||
|
||||
typedef struct CJob {
|
||||
struct CJob *next;
|
||||
CJobFn fn;
|
||||
void *arg;
|
||||
int32_t id;
|
||||
} CJob;
|
||||
|
||||
typedef struct {
|
||||
SpinLock spinlock;
|
||||
CJob *cjobs;
|
||||
} CJobs;
|
||||
|
||||
extern CJobs CJOBS;
|
||||
|
||||
void cjob_init(void);
|
||||
|
||||
int32_t cjob_register(CJobFn fn, void *arg);
|
||||
void cjob_runjobs(void);
|
||||
|
||||
#endif // CJOB_CJOB_H_
|
||||
@ -1,8 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "compiler/attr.h"
|
||||
#include "hal/hal.h"
|
||||
#include "gdt.h"
|
||||
#include "cpu/gdt.h"
|
||||
#include "std/string.h"
|
||||
|
||||
#define GDT_PRESENT 0x80
|
||||
#define GDT_TSS 0x89
|
||||
@ -43,7 +43,7 @@ void gdt_setentry(GdtEntry *ent, uint32_t base, uint32_t limit, uint8_t acc, uin
|
||||
}
|
||||
|
||||
void gdt_init(void) {
|
||||
hal_memset(&tss, 0, sizeof(tss));
|
||||
memset(&tss, 0, sizeof(tss));
|
||||
tss.iopb_off = sizeof(tss);
|
||||
|
||||
tss.rsp0 = (uint64_t)(kernelstack + sizeof(kernelstack));
|
||||
@ -1,5 +1,8 @@
|
||||
#ifndef HAL_GDT_H_
|
||||
#define HAL_GDT_H_
|
||||
#ifndef CPU_GDT_H_
|
||||
#define CPU_GDT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "compiler/attr.h"
|
||||
|
||||
#define KCODE 0x08
|
||||
#define KDATA 0x10
|
||||
@ -23,4 +26,4 @@ ALIGNED(16) extern Tss tss;
|
||||
|
||||
void gdt_init(void);
|
||||
|
||||
#endif // HAL_GDT_H_
|
||||
#endif // CPU_GDT_H_
|
||||
10
kernel/cpu/hang.c
Normal file
10
kernel/cpu/hang.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include "cpu/hang.h"
|
||||
#include "intr/intr.h"
|
||||
|
||||
void cpu_hang(void) {
|
||||
intr_disable();
|
||||
for(;;) {
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
6
kernel/cpu/hang.h
Normal file
6
kernel/cpu/hang.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef CPU_HANG_H_
|
||||
#define CPU_HANG_H_
|
||||
|
||||
void cpu_hang(void);
|
||||
|
||||
#endif // CPU_HANG_H_
|
||||
@ -1,22 +1,16 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "dev.h"
|
||||
#include "std/string.h"
|
||||
#include "dev/dev.h"
|
||||
#include "dev/ps2kbdev.h"
|
||||
#include "hshtb.h"
|
||||
#include "hal/hal.h"
|
||||
#include "termdev.h"
|
||||
#include "ps2kbdev.h"
|
||||
#include "serialdev.h"
|
||||
#include "fbdev.h"
|
||||
|
||||
DevTable DEVTABLE;
|
||||
|
||||
void dev_init(void) {
|
||||
hal_memset(&DEVTABLE, 0, sizeof(DEVTABLE));
|
||||
memset(&DEVTABLE, 0, sizeof(DEVTABLE));
|
||||
spinlock_init(&DEVTABLE.spinlock);
|
||||
|
||||
termdev_init();
|
||||
ps2kbdev_init();
|
||||
serialdev_init();
|
||||
fbdev_init();
|
||||
}
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "fbdev.h"
|
||||
#include "dev.h"
|
||||
#include "sysdefs/dev.h"
|
||||
#include "hshtb.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "util/util.h"
|
||||
#include "hal/hal.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "errors.h"
|
||||
|
||||
int32_t fbdev_getinfo(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)pid;
|
||||
|
||||
if (len != sizeof(FbDevGetInfo)) {
|
||||
return E_INVALIDARGUMENT;
|
||||
}
|
||||
|
||||
FbDevGetInfo info = {
|
||||
.w = BOOT_INFO.fb->width,
|
||||
.h = BOOT_INFO.fb->height,
|
||||
.margin = 20,
|
||||
.fontw = 8,
|
||||
.fonth = 16,
|
||||
};
|
||||
hal_memcpy(buffer, &info, sizeof(info));
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
void fbdev_init(void) {
|
||||
Dev *fbdev;
|
||||
HSHTB_ALLOC(DEVTABLE.devs, ident, "fbdev", fbdev);
|
||||
fbdev->fns[DEV_FBDEV_GETINFO] = &fbdev_getinfo;
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef DEV_FBDEV_H_
|
||||
#define DEV_FBDEV_H_
|
||||
|
||||
void fbdev_init(void);
|
||||
|
||||
#endif // DEV_FBDEV_H_
|
||||
@ -1,15 +1,17 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
#include "ps2kbdev.h"
|
||||
#include "dev.h"
|
||||
#include "errors.h"
|
||||
#include "dev/ps2kbdev.h"
|
||||
#include "dev/dev.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "util/util.h"
|
||||
#include "hshtb.h"
|
||||
#include "sysdefs/dev.h"
|
||||
#include "proc/proc.h"
|
||||
#include "io/io.h"
|
||||
#include "ipc/mbus/mbus.h"
|
||||
#include "intr/intr.h"
|
||||
#include "errors.h"
|
||||
#include "hshtb.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
#define KB_CTL_STATUS 0x64
|
||||
#define KB_DATA_IN_BUF 0x01
|
||||
@ -115,7 +117,7 @@ static uint8_t ctlmap[256] =
|
||||
[0xc7] KB_HOME,
|
||||
};
|
||||
|
||||
int32_t ps2kb_intr(void) {
|
||||
int32_t ps2kbdev_keycode(void) {
|
||||
static uint8_t shift;
|
||||
static uint8_t *charcode[4] = { normalmap, shiftmap, ctlmap, ctlmap };
|
||||
uint32_t st, data, c;
|
||||
@ -152,110 +154,23 @@ int32_t ps2kb_intr(void) {
|
||||
return c;
|
||||
}
|
||||
|
||||
typedef struct Ps2kbEvConsumer {
|
||||
struct Ps2kbEvConsumer *next;
|
||||
Proc *proc;
|
||||
RBuf rbuf;
|
||||
} Ps2kbEvConsumer;
|
||||
IpcMBus *PS2KB_MBUS;
|
||||
|
||||
struct {
|
||||
SpinLock spinlock;
|
||||
Ps2kbEvConsumer *list;
|
||||
} PS2KB_CONSUMERS = {0};
|
||||
void ps2kbdev_intr(IntrStackFrame *frame) {
|
||||
(void)frame;
|
||||
|
||||
int32_t ps2kbdev_readch(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)buffer; (void)len;
|
||||
|
||||
Proc *consproc = NULL;
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc, *proctmp;
|
||||
LL_FOREACH_SAFE(PROCS.procs, proc, proctmp) {
|
||||
if (proc->pid == pid) {
|
||||
consproc = proc;
|
||||
}
|
||||
}
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
if (consproc == NULL) {
|
||||
return E_INVALIDOPER;
|
||||
}
|
||||
|
||||
uint8_t b;
|
||||
int32_t r = -1;
|
||||
|
||||
spinlock_acquire(&PS2KB_CONSUMERS.spinlock);
|
||||
Ps2kbEvConsumer *cons, *constmp;
|
||||
LL_FOREACH_SAFE(PS2KB_CONSUMERS.list, cons, constmp) {
|
||||
if (cons->proc == consproc) {
|
||||
r = rbuf_pop(&cons->rbuf, &b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spinlock_release(&PS2KB_CONSUMERS.spinlock);
|
||||
|
||||
if (r == 0) {
|
||||
return b;
|
||||
} else {
|
||||
return E_NOTYET;
|
||||
}
|
||||
}
|
||||
|
||||
#define CONSUMER_RBUF_MAX 0x400
|
||||
|
||||
int32_t ps2kbdev_attchcons(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)buffer; (void)len;
|
||||
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc, *proctmp;
|
||||
LL_FOREACH_SAFE(PROCS.procs, proc, proctmp) {
|
||||
if (proc->pid == pid) {
|
||||
Ps2kbEvConsumer *cons = dlmalloc(sizeof(*cons));
|
||||
cons->proc = proc;
|
||||
uint8_t *buf = dlmalloc(CONSUMER_RBUF_MAX);
|
||||
rbuf_init(&cons->rbuf, buf, CONSUMER_RBUF_MAX);
|
||||
spinlock_acquire(&PS2KB_CONSUMERS.spinlock);
|
||||
LL_APPEND(PS2KB_CONSUMERS.list, cons);
|
||||
spinlock_release(&PS2KB_CONSUMERS.spinlock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
void ps2kbdev_intr(void) {
|
||||
int32_t c = ps2kb_intr();
|
||||
int32_t c = ps2kbdev_keycode();
|
||||
if (c >= 0) {
|
||||
uint8_t b = c;
|
||||
spinlock_acquire(&PS2KB_CONSUMERS.spinlock);
|
||||
Ps2kbEvConsumer *cons, *constmp;
|
||||
LL_FOREACH_SAFE(PS2KB_CONSUMERS.list, cons, constmp) {
|
||||
bool found = false;
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc, *proctmp;
|
||||
LL_FOREACH_SAFE(PROCS.procs, proc, proctmp) {
|
||||
if (proc == cons->proc) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
LL_REMOVE(PS2KB_CONSUMERS.list, cons);
|
||||
}
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
rbuf_push(&cons->rbuf, b);
|
||||
}
|
||||
spinlock_release(&PS2KB_CONSUMERS.spinlock);
|
||||
ipc_mbuspublish("ps2kb", &b);
|
||||
}
|
||||
}
|
||||
|
||||
void ps2kbdev_init(void) {
|
||||
intr_attchhandler(&ps2kbdev_intr, INTR_IRQBASE+1);
|
||||
|
||||
Dev *ps2kbdev;
|
||||
HSHTB_ALLOC(DEVTABLE.devs, ident, "ps2kbdev", ps2kbdev);
|
||||
spinlock_init(&ps2kbdev->spinlock);
|
||||
spinlock_init(&PS2KB_CONSUMERS.spinlock);
|
||||
ps2kbdev->fns[DEV_PS2KBDEV_READCH] = &ps2kbdev_readch;
|
||||
ps2kbdev->fns[DEV_PS2KBDEV_ATTCHCONS] = &ps2kbdev_attchcons;
|
||||
PS2KB_MBUS = ipc_mbusmake("ps2kb", 1, 0x100);
|
||||
|
||||
intr_attchhandler(&ps2kbdev_intr, INTR_IRQBASE+1);
|
||||
}
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "dev.h"
|
||||
#include "serialdev.h"
|
||||
#include "errors.h"
|
||||
#include "util/util.h"
|
||||
#include "hshtb.h"
|
||||
#include "sysdefs/dev.h"
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
|
||||
// https://wiki.osdev.org/Serial_Ports
|
||||
|
||||
#define PORT 0x3f8
|
||||
|
||||
void serial_init(void) {
|
||||
io_out8(PORT+1, 0x00);
|
||||
io_out8(PORT+3, 0x80);
|
||||
io_out8(PORT+0, 0x03);
|
||||
io_out8(PORT+1, 0x00);
|
||||
io_out8(PORT+3, 0x03);
|
||||
io_out8(PORT+2, 0xC7);
|
||||
io_out8(PORT+4, 0x0B);
|
||||
io_out8(PORT+4, 0x1E);
|
||||
io_out8(PORT+0, 0xAE);
|
||||
|
||||
if (io_in8(PORT+0) != 0xAE) {
|
||||
ERR("serial", "serial is faulty!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
io_out8(PORT+4, 0x0F);
|
||||
}
|
||||
|
||||
int serial_recvready(void) {
|
||||
return io_in8(PORT+5) & 1;
|
||||
}
|
||||
|
||||
uint8_t serial_recvb(void) {
|
||||
return io_in8(PORT);
|
||||
}
|
||||
|
||||
int serial_sendready(void) {
|
||||
return io_in8(PORT+5) & 0x20;
|
||||
}
|
||||
|
||||
void serial_sendb(uint8_t b) {
|
||||
io_out8(PORT, b);
|
||||
}
|
||||
|
||||
int32_t serialdev_sendb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)len; (void)pid;
|
||||
serial_sendb(buffer[0]);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t serialdev_sendready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)buffer; (void)len; (void)pid;
|
||||
return serial_sendready();
|
||||
}
|
||||
|
||||
int32_t serialdev_recvb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)buffer; (void)len; (void)pid;
|
||||
return serial_recvb();
|
||||
}
|
||||
|
||||
int32_t serialdev_recvready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)buffer; (void)len; (void)pid;
|
||||
return serial_recvready();
|
||||
}
|
||||
|
||||
void serialdev_init(void) {
|
||||
Dev *serialdev = NULL;
|
||||
HSHTB_ALLOC(DEVTABLE.devs, ident, "serialdev", serialdev);
|
||||
serialdev->fns[DEV_SERIALDEV_SENDB] = &serialdev_sendb;
|
||||
serialdev->fns[DEV_SERIALDEV_SENDREADY] = &serialdev_sendready;
|
||||
serialdev->fns[DEV_SERIALDEV_RECVB] = &serialdev_recvb;
|
||||
serialdev->fns[DEV_SERIALDEV_RECVREADY] = &serialdev_recvready;
|
||||
spinlock_init(&serialdev->spinlock);
|
||||
serial_init();
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef DEV_SERIALDEV_H_
|
||||
#define DEV_SERIALDEV_H_
|
||||
|
||||
void serialdev_init(void);
|
||||
|
||||
#endif // DEV_SERIALDEV_H_
|
||||
@ -1,23 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
#include "termdev.h"
|
||||
#include "dev.h"
|
||||
#include "errors.h"
|
||||
#include "util/util.h"
|
||||
#include "hshtb.h"
|
||||
#include "sysdefs/dev.h"
|
||||
|
||||
int32_t termdev_putch(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)dev; (void)pid;
|
||||
kprintf("%.*s", (int)len, (char *)buffer);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
void termdev_init(void) {
|
||||
Dev *termdev = NULL;
|
||||
HSHTB_ALLOC(DEVTABLE.devs, ident, "termdev", termdev);
|
||||
termdev->fns[DEV_TERMDEV_PUTCH] = &termdev_putch;
|
||||
spinlock_init(&termdev->spinlock);
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#ifndef DEV_TERMDEV_H_
|
||||
#define DEV_TERMDEV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "dev.h"
|
||||
|
||||
void termdev_init(void);
|
||||
|
||||
#endif // DEV_TERMDEV_H_
|
||||
@ -1,7 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "storedev/storedev.h"
|
||||
#include "mbr.h"
|
||||
#include "diskpart/mbr.h"
|
||||
#include "util/util.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
|
||||
@ -2,14 +2,14 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "storedev/storedev.h"
|
||||
#include "mbr.h"
|
||||
#include "diskpart.h"
|
||||
#include "diskpart/mbr.h"
|
||||
#include "diskpart/diskpart.h"
|
||||
#include "compiler/attr.h"
|
||||
#include "errors.h"
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
#include "util/util.h"
|
||||
#include "dev/dev.h"
|
||||
#include "std/string.h"
|
||||
#include "errors.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t driveattrs;
|
||||
@ -52,7 +52,7 @@ void diskpart_mbr_expose_partitions(StoreDev *sd, MBR *mbr) {
|
||||
};
|
||||
|
||||
char name1[100];
|
||||
ksprintf(name1, "%s-part%zu", name, i+1);
|
||||
ksprintf(name1, "%sp%zu", name, i+1);
|
||||
kprintf("%s\n", name1);
|
||||
storedev_create(STOREDEV_PARTSD, name1, &extra);
|
||||
}
|
||||
@ -62,7 +62,7 @@ bool diskpart_mbr_probe(StoreDev *sd) {
|
||||
LOG("diskpart", "probing for MBR\n");
|
||||
|
||||
MBR mbr;
|
||||
hal_memset(&mbr, 0, sizeof(mbr));
|
||||
memset(&mbr, 0, sizeof(mbr));
|
||||
sd->read(sd, (uint8_t *const)&mbr, 0, 0, sizeof(mbr));
|
||||
|
||||
if (!(mbr.validsign[0] == 0x55 && mbr.validsign[1] == 0xAA)) {
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
// Config
|
||||
|
||||
#include <stddef.h>
|
||||
#include "hal/hal.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "kprintf.h"
|
||||
#include "bitmap/bitmap.h"
|
||||
#include "util/util.h"
|
||||
#include "pmm/pmm.h"
|
||||
#include "malloc.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "std/string.h"
|
||||
#include "vmm/vmm.h"
|
||||
#include "cpu/hang.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
#define USE_DL_PREFIX 1
|
||||
#define LACKS_SYS_TYPES_H 1
|
||||
@ -26,7 +28,7 @@
|
||||
#define ABORT \
|
||||
do { \
|
||||
ERR("dlmalloc", "Aborting..."); \
|
||||
hal_hang(); \
|
||||
cpu_hang(); \
|
||||
} while(0)
|
||||
#define MALLOC_FAILURE_ACTION
|
||||
#define HAVE_MORECORE 1
|
||||
@ -67,7 +69,7 @@ void *sbrk(long inc) {
|
||||
|
||||
uint64_t blocks = _DIV_ROUNDUP(inc, BITMAP_BLOCK_SIZE);
|
||||
uint8_t *virt = VIRT(pmm_alloc(blocks));
|
||||
hal_memset(virt, 0, blocks * BITMAP_BLOCK_SIZE);
|
||||
memset(virt, 0, blocks * BITMAP_BLOCK_SIZE);
|
||||
_last = (void *)(virt + inc);
|
||||
return virt;
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
CFLAGS += -DKPRINTF_COLORS
|
||||
@ -1,345 +0,0 @@
|
||||
unsigned char FM_T_437_F16[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0x81, 0xa5, 0xa5, 0x81, 0x81,
|
||||
0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0xff, 0xff,
|
||||
0xdb, 0xdb, 0xff, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x22, 0x22, 0x77, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f,
|
||||
0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c,
|
||||
0x1c, 0x08, 0x6b, 0x7f, 0x7f, 0x6b, 0x08, 0x1c, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x1c, 0x3e, 0x7f, 0x7f, 0x7f, 0x7f, 0x2a, 0x08, 0x1c,
|
||||
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x7e,
|
||||
0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xc3,
|
||||
0xc3, 0x81, 0x81, 0x81, 0x81, 0x81, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24,
|
||||
0x18, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xdb, 0xdb, 0xbd, 0xbd, 0xbd,
|
||||
0xbd, 0xbd, 0xdb, 0xdb, 0xe7, 0xff, 0xff, 0xff, 0x00, 0x0f, 0x03, 0x05,
|
||||
0x05, 0x08, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x22, 0x41, 0x41, 0x41, 0x41, 0x22, 0x1c, 0x08, 0x08, 0x3e,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x0c, 0x0a, 0x0a, 0x09, 0x09, 0x09,
|
||||
0x08, 0x08, 0x38, 0x78, 0x78, 0x30, 0x00, 0x00, 0x00, 0x3f, 0x21, 0x3f,
|
||||
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x67, 0xe7, 0xe2, 0x40, 0x00,
|
||||
0x00, 0x49, 0x49, 0x2a, 0x36, 0x14, 0x22, 0xe3, 0x22, 0x14, 0x36, 0x2a,
|
||||
0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7e,
|
||||
0x7c, 0x78, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06,
|
||||
0x0e, 0x1e, 0x3e, 0x7e, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a,
|
||||
0x1c, 0x08, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0x00, 0x3f, 0x49, 0x49,
|
||||
0x49, 0x49, 0x39, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x40, 0x20, 0x58, 0x44, 0x22, 0x1a, 0x04, 0x02,
|
||||
0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x2a,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x02, 0x7f, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x7f, 0x20, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e,
|
||||
0x1c, 0x1c, 0x08, 0x08, 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, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24,
|
||||
0x7e, 0x24, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x00, 0x00,
|
||||
0x00, 0x08, 0x1e, 0x2b, 0x28, 0x28, 0x28, 0x1c, 0x0a, 0x0a, 0x0a, 0x6a,
|
||||
0x3c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x52, 0x54, 0x64, 0x08, 0x08,
|
||||
0x10, 0x10, 0x26, 0x2a, 0x4a, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44,
|
||||
0x44, 0x44, 0x28, 0x18, 0x24, 0x45, 0x42, 0x42, 0x42, 0x3d, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00,
|
||||
0x00, 0x00, 0x08, 0x49, 0x2a, 0x1c, 0x1c, 0x7f, 0x1c, 0x1c, 0x2a, 0x49,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x08, 0x10, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
|
||||
0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x80, 0x80, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24,
|
||||
0x24, 0x18, 0x00, 0x00, 0x00, 0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x02, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x02, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x0c, 0x14, 0x14, 0x24, 0x24,
|
||||
0x44, 0x44, 0x44, 0x7e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40,
|
||||
0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x42, 0x42, 0x04, 0x04, 0x04,
|
||||
0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
|
||||
0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, 0x20, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00,
|
||||
0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20,
|
||||
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x02, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x41, 0x49, 0x55, 0x55, 0x55,
|
||||
0x55, 0x55, 0x57, 0x4b, 0x20, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x24, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
|
||||
0x00, 0x7c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x7c, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x42, 0x22, 0x1c, 0x00, 0x00, 0x00, 0x78, 0x24, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x24, 0x78, 0x00, 0x00,
|
||||
0x00, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7c,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42,
|
||||
0x40, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42, 0x22, 0x1c, 0x00, 0x00,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00,
|
||||
0x00, 0x42, 0x42, 0x44, 0x44, 0x48, 0x50, 0x50, 0x68, 0x48, 0x44, 0x44,
|
||||
0x42, 0x42, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x41, 0x63, 0x63,
|
||||
0x55, 0x55, 0x49, 0x49, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00,
|
||||
0x00, 0x42, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42,
|
||||
0x42, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42,
|
||||
0x42, 0x42, 0x44, 0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x52, 0x4a, 0x44,
|
||||
0x44, 0x3a, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c,
|
||||
0x48, 0x48, 0x44, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x40, 0x40, 0x40, 0x3c, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x22, 0x22, 0x22, 0x14, 0x1c, 0x08, 0x00, 0x00,
|
||||
0x00, 0x41, 0x41, 0x41, 0x41, 0x49, 0x49, 0x49, 0x49, 0x55, 0x55, 0x55,
|
||||
0x22, 0x22, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x36, 0x14, 0x08, 0x08,
|
||||
0x08, 0x14, 0x36, 0x22, 0x41, 0x41, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22,
|
||||
0x22, 0x14, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x00, 0x7e, 0x02, 0x02, 0x04, 0x04, 0x08, 0x18, 0x10, 0x20, 0x20, 0x40,
|
||||
0x40, 0x7e, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
|
||||
0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x02, 0x02, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x04,
|
||||
0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
|
||||
0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x3a, 0x46, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x12, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42,
|
||||
0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x3c, 0x00, 0x40, 0x40, 0x40,
|
||||
0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x0c, 0x04, 0x04,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x24, 0x18, 0x00, 0x40, 0x40, 0x40,
|
||||
0x40, 0x42, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00,
|
||||
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6d, 0x49,
|
||||
0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x32, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40,
|
||||
0x40, 0x3c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,
|
||||
0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x12, 0x0c, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41,
|
||||
0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x66, 0x24, 0x18, 0x24, 0x66,
|
||||
0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7e, 0x02, 0x04, 0x04, 0x18, 0x20, 0x20, 0x40, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00,
|
||||
0x00, 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28,
|
||||
0x44, 0x82, 0x82, 0x82, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x42,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x22, 0x1c, 0x08, 0x38,
|
||||
0x00, 0x42, 0x42, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x46, 0x3a, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44,
|
||||
0x00, 0x38, 0x44, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00,
|
||||
0x00, 0x44, 0x44, 0x00, 0x00, 0x38, 0x44, 0x04, 0x3c, 0x44, 0x44, 0x44,
|
||||
0x48, 0x36, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x00, 0x38, 0x44, 0x04,
|
||||
0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00, 0x00, 0x18, 0x24, 0x18,
|
||||
0x00, 0x38, 0x44, 0x04, 0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||||
0x42, 0x3c, 0x08, 0x38, 0x00, 0x18, 0x24, 0x42, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x20, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x40, 0x40,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x18, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22,
|
||||
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00,
|
||||
0x00, 0x20, 0x10, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x1c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x18, 0x24, 0x42, 0x42, 0x42,
|
||||
0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x18, 0x24, 0x18,
|
||||
0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
|
||||
0x04, 0x08, 0x7e, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49, 0x09,
|
||||
0x39, 0x4f, 0x48, 0x48, 0x49, 0x36, 0x00, 0x00, 0x00, 0x1f, 0x28, 0x48,
|
||||
0x48, 0x48, 0x48, 0x7f, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x42, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x3c, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08,
|
||||
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x18, 0x24, 0x42, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x46, 0x3a, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x00, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x42, 0x42, 0x00,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x3c,
|
||||
0x42, 0x42, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x42, 0x42, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
|
||||
0x08, 0x3e, 0x49, 0x48, 0x48, 0x48, 0x48, 0x49, 0x3e, 0x08, 0x08, 0x00,
|
||||
0x00, 0x0c, 0x12, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x08, 0x38, 0x49,
|
||||
0x49, 0x36, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x14, 0x7f, 0x08,
|
||||
0x08, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42,
|
||||
0x42, 0x44, 0x78, 0x40, 0x44, 0x5f, 0x44, 0x44, 0x45, 0x42, 0x00, 0x00,
|
||||
0x00, 0x06, 0x09, 0x09, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x48,
|
||||
0x48, 0x30, 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x00, 0x38, 0x44, 0x04,
|
||||
0x3c, 0x44, 0x44, 0x44, 0x48, 0x36, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10,
|
||||
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00,
|
||||
0x00, 0x04, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x00, 0x42, 0x42, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00,
|
||||
0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
|
||||
0x32, 0x4c, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46,
|
||||
0x42, 0x42, 0x00, 0x00, 0x00, 0x38, 0x48, 0x48, 0x34, 0x00, 0x7c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48,
|
||||
0x30, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x40, 0x42, 0x42,
|
||||
0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
||||
0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x30, 0x10, 0x10, 0x11, 0x3a, 0x04, 0x08, 0x16, 0x29, 0x42,
|
||||
0x04, 0x08, 0x0f, 0x00, 0x00, 0x10, 0x30, 0x10, 0x10, 0x11, 0x3a, 0x04,
|
||||
0x08, 0x12, 0x26, 0x4a, 0x1f, 0x02, 0x02, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24, 0x48, 0x24, 0x12, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x24, 0x12,
|
||||
0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
|
||||
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
|
||||
0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
|
||||
0x55, 0xaa, 0x55, 0xaa, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb,
|
||||
0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08,
|
||||
0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08,
|
||||
0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0xe4, 0x04, 0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x04,
|
||||
0xe4, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0xe4, 0x04, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xfc, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x08,
|
||||
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x27, 0x20, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x27, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0xe7, 0x00,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0xe7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x27, 0x20, 0x27, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0xe7, 0x00, 0xe7, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x0f, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3f, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x24, 0x24, 0x24, 0x24, 0xff, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x32, 0x4a, 0x4a, 0x44, 0x44, 0x44, 0x44, 0x4a, 0x32, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x48, 0x44, 0x42, 0x42,
|
||||
0x42, 0x4c, 0x40, 0x40, 0x00, 0x7e, 0x42, 0x42, 0x40, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00,
|
||||
0x00, 0x7f, 0x40, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40,
|
||||
0x40, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x48, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5d, 0x40, 0x40,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x4e, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x1c, 0x22, 0x41, 0x41,
|
||||
0x41, 0x22, 0x1c, 0x08, 0x08, 0x7f, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24,
|
||||
0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24,
|
||||
0x24, 0x66, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x08, 0x04, 0x1c, 0x22, 0x42,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x02, 0x04, 0x3c, 0x4a, 0x4a, 0x52, 0x52, 0x3c, 0x20,
|
||||
0x40, 0x40, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x20, 0x20, 0x40, 0x40, 0x7c,
|
||||
0x40, 0x40, 0x20, 0x20, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
|
||||
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x3e,
|
||||
0x08, 0x08, 0x08, 0x08, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
|
||||
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x7e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04,
|
||||
0x00, 0x7e, 0x00, 0x00, 0x00, 0x06, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x48, 0x48, 0x48, 0x30, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00,
|
||||
0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x48,
|
||||
0x48, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08, 0x28, 0x68, 0x28, 0x18, 0x18, 0x08, 0x00, 0x00,
|
||||
0x00, 0x58, 0x64, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x04, 0x18, 0x20, 0x3c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
unsigned int FM_T_437_F16_len = 4096;
|
||||
345
kernel/font.h
Normal file
345
kernel/font.h
Normal file
@ -0,0 +1,345 @@
|
||||
unsigned char FLORI_F16[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xc3, 0x81, 0xe7, 0x81, 0xe7,
|
||||
0xbd, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
|
||||
0xff, 0x99, 0xff, 0xbd, 0x99, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e,
|
||||
0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
|
||||
0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c,
|
||||
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd,
|
||||
0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x07,
|
||||
0x0d, 0x19, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xff, 0x81, 0x99, 0xbd, 0xff, 0x99, 0x99, 0x99, 0x99, 0x81, 0x81,
|
||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
|
||||
0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
|
||||
0x7f, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3, 0xc6,
|
||||
0xcc, 0xd8, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x1b,
|
||||
0x33, 0x63, 0xc3, 0x63, 0x33, 0x1b, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x3c, 0x7e, 0xff, 0x18, 0x18, 0x18, 0xff, 0x7e, 0x3c, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
|
||||
0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
|
||||
0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3e, 0x63, 0x30, 0x7c, 0x66, 0x33, 0x1f, 0x06, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e,
|
||||
0xff, 0x18, 0x18, 0x18, 0xff, 0x7e, 0x3c, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x3c, 0x7e, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
|
||||
0x0c, 0x0e, 0xff, 0x0e, 0x0c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x10, 0x30, 0x70, 0xff, 0x70, 0x30, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60,
|
||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc3, 0xc3, 0x66, 0x66,
|
||||
0x3c, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x3e, 0x6b, 0x68, 0x68, 0x3e, 0x0b, 0x0b, 0x6b, 0x3e,
|
||||
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xdb, 0x76, 0x0c, 0x18,
|
||||
0x30, 0x6e, 0xdb, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
|
||||
0x36, 0x3c, 0x18, 0x3b, 0x6e, 0x66, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
|
||||
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x6b, 0x3e, 0x7f, 0x3e, 0x6b, 0x08, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff,
|
||||
0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3e, 0x63, 0x63, 0x67, 0x6f, 0x7b, 0x73, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x0c, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
|
||||
0x43, 0x03, 0x0e, 0x38, 0x60, 0x60, 0x61, 0x7f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3e, 0x63, 0x43, 0x03, 0x1e, 0x03, 0x03, 0x03, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x33, 0x63, 0x63,
|
||||
0x7f, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x61,
|
||||
0x60, 0x60, 0x7e, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1e, 0x30, 0x60, 0x60, 0x7e, 0x63, 0x63, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x03, 0x03, 0x06, 0x0c,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
|
||||
0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3f, 0x03, 0x03, 0x06, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
|
||||
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
|
||||
0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3e, 0x63, 0x63, 0x03, 0x0e, 0x18, 0x18, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x6f, 0x6b, 0x6b,
|
||||
0x6b, 0x6e, 0x60, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
|
||||
0x63, 0x63, 0x63, 0xff, 0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3e, 0x63, 0xe3, 0x63, 0x7e, 0x63, 0x63, 0x63, 0x63, 0xfe,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x63, 0x60, 0x60, 0x60,
|
||||
0x60, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
|
||||
0xe3, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3f, 0x61, 0xe0, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x61, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x61, 0xe0, 0x60, 0x7c, 0x60,
|
||||
0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
|
||||
0x63, 0x60, 0x60, 0x6f, 0x63, 0x63, 0x63, 0x3f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0xe3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x38, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0e,
|
||||
0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x63, 0xe3, 0x66, 0x6c, 0x78, 0x7c, 0x66, 0x63, 0x63, 0xe3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x70, 0xe0, 0x60, 0x60, 0x60,
|
||||
0x60, 0x60, 0x61, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
|
||||
0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x63, 0xf3, 0x7b, 0x6f, 0x67, 0x63, 0x63, 0x63, 0x63, 0xe3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x63, 0x63, 0x63, 0x63,
|
||||
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
|
||||
0xe3, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1e, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7b, 0x6f, 0x3e,
|
||||
0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0xe3, 0x63, 0x63, 0x7e,
|
||||
0x6c, 0x66, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
|
||||
0x63, 0x60, 0x78, 0x1e, 0x03, 0x63, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xd9, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x63,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3,
|
||||
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63, 0x3e, 0x1c, 0x3e,
|
||||
0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
|
||||
0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3f, 0x63, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x61, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x3f,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe0,
|
||||
0x60, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x60, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03, 0x3f, 0x63, 0x63,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x63, 0x63, 0x6e, 0x78, 0x73, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1e, 0x33, 0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x63, 0x63,
|
||||
0x63, 0x67, 0x3b, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe0,
|
||||
0x60, 0x6e, 0x73, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x1b, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x06, 0x0e, 0x06,
|
||||
0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe0,
|
||||
0x60, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdb, 0xdb,
|
||||
0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x6e, 0xf3, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xf3, 0x63,
|
||||
0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x67, 0x3b, 0x03, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xf3, 0x63, 0x60, 0x60, 0x60, 0x60,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x60,
|
||||
0x3e, 0x03, 0x63, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x18,
|
||||
0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x67, 0x3b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63,
|
||||
0x63, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xe3, 0x63,
|
||||
0x63, 0x67, 0x3b, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3f, 0x66, 0x0c, 0x18, 0x30, 0x61, 0x7f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
|
||||
0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3b, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36,
|
||||
0x63, 0x63, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33,
|
||||
0x63, 0x60, 0x60, 0x60, 0x60, 0x63, 0x63, 0x3e, 0x03, 0x0e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x63, 0x63, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x67, 0x3b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x3e, 0x63, 0x63,
|
||||
0x7f, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1e, 0x33,
|
||||
0x00, 0x3e, 0x03, 0x3f, 0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x33, 0x33, 0x00, 0x3e, 0x03, 0x3f, 0x63, 0x63, 0x67, 0x3b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x03, 0x3f,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x1c,
|
||||
0x00, 0x3e, 0x03, 0x3f, 0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x60, 0x63, 0x3e,
|
||||
0x03, 0x0e, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63,
|
||||
0x7f, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33,
|
||||
0x00, 0x3e, 0x63, 0x63, 0x7f, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x60, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x00, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36,
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x18, 0x0c, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x1e, 0x33, 0x63, 0x63, 0xff,
|
||||
0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x1e,
|
||||
0x33, 0x63, 0x63, 0xff, 0x63, 0x63, 0x63, 0xe3, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x30, 0x3f, 0x61, 0xe0, 0x7c, 0x60, 0x60, 0x60, 0x61, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x1b, 0x1b,
|
||||
0xfb, 0xdf, 0xd8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x36,
|
||||
0x66, 0x66, 0x66, 0xff, 0x66, 0x66, 0x66, 0xe7, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x3e, 0x63, 0x63,
|
||||
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c,
|
||||
0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x1c, 0x36, 0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x67, 0x3b,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x00, 0x63, 0xe3, 0x63,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63,
|
||||
0x00, 0x63, 0xe3, 0x63, 0x63, 0x63, 0x3f, 0x03, 0x63, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x63, 0x63, 0x00, 0x1e, 0x33, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x63, 0xe3, 0x63, 0x63,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00,
|
||||
0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x78, 0x30, 0x30, 0x30, 0x73, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
|
||||
0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x66,
|
||||
0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x77, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0xd8,
|
||||
0x70, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x03, 0x3f,
|
||||
0x63, 0x63, 0x67, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x18, 0x30, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x63, 0xe3, 0x63,
|
||||
0x63, 0x63, 0x63, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e,
|
||||
0x00, 0x6e, 0xf3, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x3b, 0x6e, 0x00, 0x63, 0xf3, 0x7b, 0x6f, 0x67, 0x63, 0x63, 0xe3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3c, 0x00, 0x7e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
|
||||
0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x3c, 0x60, 0x63, 0x63, 0x3e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60,
|
||||
0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x60, 0xe1, 0x63, 0x66, 0x6c, 0x18, 0x36, 0x6b, 0xdb, 0x86, 0x0c,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x00, 0x60, 0xe1, 0x63, 0x66, 0x6c, 0x18, 0x33,
|
||||
0x67, 0xcb, 0x9b, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x36, 0x1b, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b,
|
||||
0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x41, 0x63, 0x36,
|
||||
0x14, 0x41, 0x63, 0x36, 0x14, 0x41, 0x63, 0x36, 0x14, 0x41, 0x63, 0x36,
|
||||
0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00, 0xdb, 0x00,
|
||||
0xdb, 0x00, 0xdb, 0x00, 0x00, 0x1c, 0x63, 0x14, 0x63, 0x1c, 0x00, 0x00,
|
||||
0x00, 0x1c, 0x63, 0x14, 0x63, 0x1c, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x00, 0xf0,
|
||||
0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0e, 0xe6,
|
||||
0x76, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x76, 0xe6, 0x0e, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x00, 0x0f, 0x1c, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x33, 0x38, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x38, 0x33, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xe3,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3b, 0x6e, 0x6c, 0x6c, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x6e, 0x63, 0x63, 0x63, 0x6e,
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x63, 0x60, 0x60, 0x60,
|
||||
0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xc3, 0x60, 0x30, 0x18, 0x18, 0x30, 0x60, 0xc3, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x6c,
|
||||
0x6c, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x70, 0x70, 0x60, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x0c, 0x0c, 0x0c, 0x0c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x7e, 0xe7, 0xc3, 0xc3,
|
||||
0xe7, 0x7e, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
|
||||
0x66, 0xc3, 0xff, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x66, 0xe7,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
|
||||
0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60,
|
||||
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x38, 0x60, 0x60, 0x7e, 0x60,
|
||||
0x60, 0x60, 0x38, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63,
|
||||
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18,
|
||||
0x18, 0x18, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
|
||||
0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x7e,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x00, 0x3b,
|
||||
0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
|
||||
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
|
||||
0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x18, 0x70, 0xc0, 0xf8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
unsigned int FLORI_F16_len = 4096;
|
||||
674
kernel/fs/fatfs/LICENSE
Normal file
674
kernel/fs/fatfs/LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
167
kernel/fs/fatfs/README.md
Normal file
167
kernel/fs/fatfs/README.md
Normal file
@ -0,0 +1,167 @@
|
||||
### FAT16/32 File System Library
|
||||
|
||||
Github: [http://github.com/ultraembedded/fat_io_lib](https://github.com/ultraembedded/fat_io_lib)
|
||||
|
||||
#### Intro
|
||||
|
||||
Designed for low memory embedded systems back in 2003, this project is a multi-purpose platform independent C code implementation of a FAT16 & FAT32 driver with read & write support.
|
||||
|
||||
The library provides stdio like interface functions such as fopen(), fgetc(), fputc(), fread(), fwrite() etc, allowing existing applications to be ported easily using a familiar API.
|
||||
The project is aimed at applications which require file system support such as MP3 players, data loggers, etc and has a low memory footprint with customizable build options to enable it to run on platforms such as the Atmel AVR, ARM & PIC microcontrollers.
|
||||
|
||||
The source code is available for free under GPL license, or alternatively, with a commercial compatible license for a small donation.
|
||||
|
||||
This library has been used in many open source projects including;
|
||||
* Aleph - Open source sound computer.
|
||||
* IV:MP - Grand Theft Auto: IV multiplayer game mod.
|
||||
* hxcfloppyemu - HxC Floppy Drive Emulator.
|
||||
|
||||
#### Features
|
||||
|
||||
* Standard file I/O API (fopen(), fread(), fwrite(), etc)
|
||||
* FAT16/FAT32 support (read + write)
|
||||
* Long filename support (optional)
|
||||
* Format function (optional)
|
||||
* Directory listing (optional)
|
||||
* Buffering & caching for higher performance (optional)
|
||||
|
||||
#### API
|
||||
|
||||
The following file IO API is provided:
|
||||
|
||||
* fopen
|
||||
* fclose
|
||||
* fread
|
||||
* fwrite
|
||||
* fputc
|
||||
* fputs
|
||||
* fgetc
|
||||
* fflush
|
||||
* fgetpos
|
||||
* fseek
|
||||
* ftell
|
||||
* feof
|
||||
* remove
|
||||
|
||||
Just add sector read & write functions for the media/platform you are using for a complete file system!
|
||||
|
||||
#### Testing
|
||||
|
||||
Each release of the project is tested using self verifying test benches to ensure validity and to protect against regressions (not currently released).
|
||||
|
||||
#### Commercial
|
||||
|
||||
If you would like to use this code in a commercial project with a closed source compatible license, please contact me.
|
||||
|
||||
#### Configuration
|
||||
See the following defines in src/fat_opts.h:
|
||||
|
||||
```
|
||||
FATFS_IS_LITTLE_ENDIAN [1/0]
|
||||
Which endian is your system? Set to 1 for little endian, 0 for big endian.
|
||||
|
||||
FATFS_MAX_LONG_FILENAME [260]
|
||||
By default, 260 characters (max LFN length). Increase this to support greater path depths.
|
||||
|
||||
FATFS_MAX_OPEN_FILES
|
||||
The more files you wish to have concurrently open, the greater this number should be.
|
||||
This increases the number of FL_FILE file structures in the library, each of these is around 1K in size (assuming 512 byte sectors).
|
||||
|
||||
FAT_BUFFER_SECTORS
|
||||
Minimum is 1, more increases performance.
|
||||
This defines how many FAT sectors can be buffered per FAT_BUFFER entry.
|
||||
|
||||
FAT_BUFFERS
|
||||
Minimum is 1, more increases performance.
|
||||
This defines how many FAT buffer entries are available.
|
||||
Memory usage is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE
|
||||
|
||||
FATFS_INC_WRITE_SUPPORT
|
||||
Support file write functionality.
|
||||
|
||||
FAT_SECTOR_SIZE
|
||||
Sector size used by buffers. Most likely to be 512 bytes (standard for ATA/IDE).
|
||||
|
||||
FAT_PRINTF
|
||||
A define that allows the File IO library to print to console/stdout.
|
||||
Provide your own printf function if printf not available.
|
||||
|
||||
FAT_CLUSTER_CACHE_ENTRIES
|
||||
Size of cluster chain cache (can be undefined if not required).
|
||||
Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
|
||||
Improves access speed considerably.
|
||||
|
||||
FATFS_INC_LFN_SUPPORT [1/0]
|
||||
Enable/Disable support for long filenames.
|
||||
|
||||
FATFS_DIR_LIST_SUPPORT [1/0]
|
||||
Include support for directory listing.
|
||||
|
||||
FATFS_INC_TIME_DATE_SUPPORT [1/0]
|
||||
Use time/date functions provided by time.h to update creation & modification timestamps.
|
||||
|
||||
FATFS_INC_FORMAT_SUPPORT
|
||||
Include support for formatting disks (FAT16 only).
|
||||
|
||||
FAT_PRINTF_NOINC_STDIO
|
||||
Disable use of printf & inclusion of stdio.h
|
||||
```
|
||||
|
||||
|
||||
#### Interfacing to storage media
|
||||
```
|
||||
-----------------------------------------------------------------
|
||||
int media_read(uint32 sector, uint8 *buffer, uint32 sector_count)
|
||||
-----------------------------------------------------------------
|
||||
Params:
|
||||
Sector: 32-bit sector number
|
||||
Buffer: Target buffer to read n sectors of data into.
|
||||
Sector_count: Number of sectors to read
|
||||
|
||||
Return:
|
||||
int, 1 = success, 0 = failure.
|
||||
|
||||
Description:
|
||||
Application/target specific disk/media read function.
|
||||
Sector number (sectors are usually 512 byte pages) to read.
|
||||
|
||||
-----------------------------------------------------------------
|
||||
int media_write(uint32 sector, uint8 *buffer, uint32 sector_count)
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Params:
|
||||
Sector: 32-bit sector number
|
||||
Buffer: Target buffer to write n sectors of data from.
|
||||
Sector_count: Number of sectors to write.
|
||||
|
||||
Return:
|
||||
int, 1 = success, 0 = failure.
|
||||
|
||||
Description:
|
||||
Application/target specific disk/media write function.
|
||||
Sector number (sectors are usually 512 byte pages) to write to.
|
||||
|
||||
|
||||
-----------------------------------------------------------------
|
||||
Use the following API to attach the media IO functions to the File IO library;
|
||||
|
||||
fl_attach_media(media_read, media_write);
|
||||
```
|
||||
|
||||
#### History
|
||||
|
||||
* v2.6.11 - Fix compilation with GCC on 64-bit machines
|
||||
* v2.6.10 - Added support for FAT32 format.
|
||||
* v2.6.9 - Added support for time & date handling.
|
||||
* v2.6.8 - Fixed error with FSINFO sector write.
|
||||
* v2.6.7 - Added fgets(). Fixed C warnings, removed dependency on some string.h functions.
|
||||
* v2.6.6 - Massive read + write performance improvements.
|
||||
* v2.6.5 - Bug fixes for big endian systems.
|
||||
* v2.6.4 - Further bug fixes and performance improvements for write operations.
|
||||
* v2.6.3 - Performance improvements, FAT16 formatting support. Various bug fixes
|
||||
* v2.6 - Basic support for FAT16 added
|
||||
* v2.5 - Code cleaned up. Many bugs fixed. Thread safety functions added.
|
||||
* v2.x - Write support added as well as better stdio like API.
|
||||
* v1.0 - Rewrite of all code to enable multiple files to be opened and provides a better file API.
|
||||
* v0.1b - fopen(), fgetc(), fopenDIR() using new software stack for IDE drives and FAT32 access.
|
||||
* v0.1a - First release; fopen(), fgetc() unbuffered reads.... (27/12/03)
|
||||
905
kernel/fs/fatfs/fat_access.c
Normal file
905
kernel/fs/fatfs/fat_access.c
Normal file
@ -0,0 +1,905 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include "fat_defs.h"
|
||||
#include "fat_access.h"
|
||||
#include "fat_table.h"
|
||||
#include "fat_write.h"
|
||||
#include "fat_string.h"
|
||||
#include "fat_misc.h"
|
||||
#include "fat_context.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_init: Load FAT Parameters
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_init(struct fat_ctx *ctx, struct fatfs *fs)
|
||||
{
|
||||
uint8 num_of_fats;
|
||||
uint16 reserved_sectors;
|
||||
uint32 FATSz;
|
||||
uint32 root_dir_sectors;
|
||||
uint32 total_sectors;
|
||||
uint32 data_sectors;
|
||||
uint32 count_of_clusters;
|
||||
uint8 valid_partition = 0;
|
||||
|
||||
fs->currentsector.address = FAT32_INVALID_CLUSTER;
|
||||
fs->currentsector.dirty = 0;
|
||||
|
||||
fs->next_free_cluster = 0; // Invalid
|
||||
|
||||
fatfs_fat_init(fs);
|
||||
|
||||
// Make sure we have a read function (write function is optional)
|
||||
if (!fs->disk_io.read_media)
|
||||
return FAT_INIT_MEDIA_ACCESS_ERROR;
|
||||
|
||||
// MBR: Sector 0 on the disk
|
||||
// NOTE: Some removeable media does not have this.
|
||||
|
||||
// Load MBR (LBA 0) into the 512 byte buffer
|
||||
if (!fs->disk_io.read_media(ctx, 0, fs->currentsector.sector, 1))
|
||||
return FAT_INIT_MEDIA_ACCESS_ERROR;
|
||||
|
||||
// Make Sure 0x55 and 0xAA are at end of sector
|
||||
// (this should be the case regardless of the MBR or boot sector)
|
||||
if (fs->currentsector.sector[SIGNATURE_POSITION] != 0x55 || fs->currentsector.sector[SIGNATURE_POSITION+1] != 0xAA)
|
||||
return FAT_INIT_INVALID_SIGNATURE;
|
||||
|
||||
// Now check again using the access function to prove endian conversion function
|
||||
if (GET_16BIT_WORD(fs->currentsector.sector, SIGNATURE_POSITION) != SIGNATURE_VALUE)
|
||||
return FAT_INIT_ENDIAN_ERROR;
|
||||
|
||||
// Verify packed structures
|
||||
if (sizeof(struct fat_dir_entry) != FAT_DIR_ENTRY_SIZE)
|
||||
return FAT_INIT_STRUCT_PACKING;
|
||||
|
||||
// Check the partition type code
|
||||
switch(fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION])
|
||||
{
|
||||
case 0x0B:
|
||||
case 0x06:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
case 0x05:
|
||||
valid_partition = 1;
|
||||
break;
|
||||
case 0x00:
|
||||
valid_partition = 0;
|
||||
break;
|
||||
default:
|
||||
if (fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION] <= 0x06)
|
||||
valid_partition = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Read LBA Begin for the file system
|
||||
if (valid_partition)
|
||||
fs->lba_begin = GET_32BIT_WORD(fs->currentsector.sector, PARTITION1_LBA_BEGIN_LOCATION);
|
||||
// Else possibly MBR less disk
|
||||
else
|
||||
fs->lba_begin = 0;
|
||||
|
||||
// Load Volume 1 table into sector buffer
|
||||
// (We may already have this in the buffer if MBR less drive!)
|
||||
if (!fs->disk_io.read_media(ctx, fs->lba_begin, fs->currentsector.sector, 1))
|
||||
return FAT_INIT_MEDIA_ACCESS_ERROR;
|
||||
|
||||
// Make sure there are 512 bytes per cluster
|
||||
if (GET_16BIT_WORD(fs->currentsector.sector, 0x0B) != FAT_SECTOR_SIZE)
|
||||
return FAT_INIT_INVALID_SECTOR_SIZE;
|
||||
|
||||
// Load Parameters of FAT partition
|
||||
fs->sectors_per_cluster = fs->currentsector.sector[BPB_SECPERCLUS];
|
||||
reserved_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT);
|
||||
num_of_fats = fs->currentsector.sector[BPB_NUMFATS];
|
||||
fs->root_entry_count = GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT);
|
||||
|
||||
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)
|
||||
fs->fat_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);
|
||||
else
|
||||
fs->fat_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);
|
||||
|
||||
// For FAT32 (which this may be)
|
||||
fs->rootdir_first_cluster = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_ROOTCLUS);
|
||||
fs->fs_info_sector = GET_16BIT_WORD(fs->currentsector.sector, BPB_FAT32_FSINFO);
|
||||
|
||||
// For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
|
||||
fs->rootdir_first_sector = reserved_sectors + (num_of_fats * fs->fat_sectors);
|
||||
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
|
||||
|
||||
// First FAT LBA address
|
||||
fs->fat_begin_lba = fs->lba_begin + reserved_sectors;
|
||||
|
||||
// The address of the first data cluster on this volume
|
||||
fs->cluster_begin_lba = fs->fat_begin_lba + (num_of_fats * fs->fat_sectors);
|
||||
|
||||
if (GET_16BIT_WORD(fs->currentsector.sector, 0x1FE) != 0xAA55) // This signature should be AA55
|
||||
return FAT_INIT_INVALID_SIGNATURE;
|
||||
|
||||
// Calculate the root dir sectors
|
||||
root_dir_sectors = ((GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT) * 32) + (GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC) - 1)) / GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC);
|
||||
|
||||
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)
|
||||
FATSz = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);
|
||||
else
|
||||
FATSz = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);
|
||||
|
||||
if(GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16) != 0)
|
||||
total_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16);
|
||||
else
|
||||
total_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_TOTSEC32);
|
||||
|
||||
data_sectors = total_sectors - (GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT) + (fs->currentsector.sector[BPB_NUMFATS] * FATSz) + root_dir_sectors);
|
||||
|
||||
// Find out which version of FAT this is...
|
||||
if (fs->sectors_per_cluster != 0)
|
||||
{
|
||||
count_of_clusters = data_sectors / fs->sectors_per_cluster;
|
||||
|
||||
if(count_of_clusters < 4085)
|
||||
// Volume is FAT12
|
||||
return FAT_INIT_WRONG_FILESYS_TYPE;
|
||||
else if(count_of_clusters < 65525)
|
||||
{
|
||||
// Clear this FAT32 specific param
|
||||
fs->rootdir_first_cluster = 0;
|
||||
|
||||
// Volume is FAT16
|
||||
fs->fat_type = FAT_TYPE_16;
|
||||
return FAT_INIT_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Volume is FAT32
|
||||
fs->fat_type = FAT_TYPE_32;
|
||||
return FAT_INIT_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
return FAT_INIT_WRONG_FILESYS_TYPE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lba_of_cluster: This function converts a cluster number into a sector /
|
||||
// LBA number.
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number)
|
||||
{
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
return (fs->cluster_begin_lba + (fs->root_entry_count * 32 / FAT_SECTOR_SIZE) + ((Cluster_Number-2) * fs->sectors_per_cluster));
|
||||
else
|
||||
return ((fs->cluster_begin_lba + ((Cluster_Number-2)*fs->sectors_per_cluster)));
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_sector_read:
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_sector_read(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)
|
||||
{
|
||||
return fs->disk_io.read_media(ctx, lba, target, count);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_sector_write:
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_sector_write(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)
|
||||
{
|
||||
return fs->disk_io.write_media(ctx, lba, target, count);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_sector_reader: From the provided startcluster and sector offset
|
||||
// Returns True if success, returns False if not (including if read out of range)
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_sector_reader(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster, uint32 offset, uint8 *target)
|
||||
{
|
||||
uint32 sector_to_read = 0;
|
||||
uint32 cluster_to_read = 0;
|
||||
uint32 cluster_chain = 0;
|
||||
uint32 i;
|
||||
uint32 lba;
|
||||
|
||||
// FAT16 Root directory
|
||||
if (fs->fat_type == FAT_TYPE_16 && start_cluster == 0)
|
||||
{
|
||||
if (offset < fs->rootdir_sectors)
|
||||
lba = fs->lba_begin + fs->rootdir_first_sector + offset;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// FAT16/32 Other
|
||||
else
|
||||
{
|
||||
// Set start of cluster chain to initial value
|
||||
cluster_chain = start_cluster;
|
||||
|
||||
// Find parameters
|
||||
cluster_to_read = offset / fs->sectors_per_cluster;
|
||||
sector_to_read = offset - (cluster_to_read*fs->sectors_per_cluster);
|
||||
|
||||
// Follow chain to find cluster to read
|
||||
for (i=0; i<cluster_to_read; i++)
|
||||
cluster_chain = fatfs_find_next_cluster(ctx, fs, cluster_chain);
|
||||
|
||||
// If end of cluster chain then return false
|
||||
if (cluster_chain == FAT32_LAST_CLUSTER)
|
||||
return 0;
|
||||
|
||||
// Calculate sector address
|
||||
lba = fatfs_lba_of_cluster(fs, cluster_chain)+sector_to_read;
|
||||
}
|
||||
|
||||
// User provided target array
|
||||
if (target)
|
||||
return fs->disk_io.read_media(ctx, lba, target, 1);
|
||||
// Else read sector if not already loaded
|
||||
else if (lba != fs->currentsector.address)
|
||||
{
|
||||
fs->currentsector.address = lba;
|
||||
return fs->disk_io.read_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_read_sector: Read from the provided cluster and sector offset
|
||||
// Returns True if success, returns False if not
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_read_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
|
||||
{
|
||||
// FAT16 Root directory
|
||||
if (fs->fat_type == FAT_TYPE_16 && cluster == 0)
|
||||
{
|
||||
uint32 lba;
|
||||
|
||||
// In FAT16, there are a limited amount of sectors in root dir!
|
||||
if (sector < fs->rootdir_sectors)
|
||||
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
|
||||
else
|
||||
return 0;
|
||||
|
||||
// User target buffer passed in
|
||||
if (target)
|
||||
{
|
||||
// Read from disk
|
||||
return fs->disk_io.read_media(ctx, lba, target, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate read address
|
||||
fs->currentsector.address = lba;
|
||||
|
||||
// Read from disk
|
||||
return fs->disk_io.read_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
}
|
||||
// FAT16/32 Other
|
||||
else
|
||||
{
|
||||
// User target buffer passed in
|
||||
if (target)
|
||||
{
|
||||
// Calculate read address
|
||||
uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;
|
||||
|
||||
// Read from disk
|
||||
return fs->disk_io.read_media(ctx, lba, target, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate write address
|
||||
fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;
|
||||
|
||||
// Read from disk
|
||||
return fs->disk_io.read_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_write_sector: Write to the provided cluster and sector offset
|
||||
// Returns True if success, returns False if not
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_write_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)
|
||||
{
|
||||
// No write access?
|
||||
if (!fs->disk_io.write_media)
|
||||
return 0;
|
||||
|
||||
// FAT16 Root directory
|
||||
if (fs->fat_type == FAT_TYPE_16 && cluster == 0)
|
||||
{
|
||||
uint32 lba;
|
||||
|
||||
// In FAT16 we cannot extend the root dir!
|
||||
if (sector < fs->rootdir_sectors)
|
||||
lba = fs->lba_begin + fs->rootdir_first_sector + sector;
|
||||
else
|
||||
return 0;
|
||||
|
||||
// User target buffer passed in
|
||||
if (target)
|
||||
{
|
||||
// Write to disk
|
||||
return fs->disk_io.write_media(ctx, lba, target, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate write address
|
||||
fs->currentsector.address = lba;
|
||||
|
||||
// Write to disk
|
||||
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
}
|
||||
// FAT16/32 Other
|
||||
else
|
||||
{
|
||||
// User target buffer passed in
|
||||
if (target)
|
||||
{
|
||||
// Calculate write address
|
||||
uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;
|
||||
|
||||
// Write to disk
|
||||
return fs->disk_io.write_media(ctx, lba, target, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate write address
|
||||
fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;
|
||||
|
||||
// Write to disk
|
||||
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_show_details: Show the details about the filesystem
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_show_details(struct fatfs *fs)
|
||||
{
|
||||
FAT_PRINTF(("FAT details:\r\n"));
|
||||
FAT_PRINTF((" Type =%s", (fs->fat_type == FAT_TYPE_32) ? "FAT32": "FAT16"));
|
||||
FAT_PRINTF((" Root Dir First Cluster = %x\r\n", fs->rootdir_first_cluster));
|
||||
FAT_PRINTF((" FAT Begin LBA = 0x%x\r\n",fs->fat_begin_lba));
|
||||
FAT_PRINTF((" Cluster Begin LBA = 0x%x\r\n",fs->cluster_begin_lba));
|
||||
FAT_PRINTF((" Sectors Per Cluster = %d\r\n", fs->sectors_per_cluster));
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_get_root_cluster: Get the root dir cluster
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 fatfs_get_root_cluster(struct fatfs *fs)
|
||||
{
|
||||
// NOTE: On FAT16 this will be 0 which has a special meaning...
|
||||
return fs->rootdir_first_cluster;
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
// fatfs_get_file_entry: Find the file entry for a filename
|
||||
//-------------------------------------------------------------
|
||||
uint32 fatfs_get_file_entry(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *name_to_find, struct fat_dir_entry *sfEntry)
|
||||
{
|
||||
uint8 item=0;
|
||||
uint16 recordoffset = 0;
|
||||
uint8 i=0;
|
||||
int x=0;
|
||||
char *long_filename = NULL;
|
||||
char short_filename[13];
|
||||
struct lfn_cache lfn;
|
||||
int dotRequired = 0;
|
||||
struct fat_dir_entry *directoryEntry;
|
||||
|
||||
fatfs_lfn_cache_init(&lfn, 1);
|
||||
|
||||
// Main cluster following loop
|
||||
while (1)
|
||||
{
|
||||
// Read sector
|
||||
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
|
||||
{
|
||||
// Analyse Sector
|
||||
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Create the multiplier for sector access
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// Overlay directory entry over buffer
|
||||
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// Long File Name Text Found
|
||||
if (fatfs_entry_lfn_text(directoryEntry) )
|
||||
fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);
|
||||
|
||||
// If Invalid record found delete any long file name information collated
|
||||
else if (fatfs_entry_lfn_invalid(directoryEntry) )
|
||||
fatfs_lfn_cache_init(&lfn, 0);
|
||||
|
||||
// Normal SFN Entry and Long text exists
|
||||
else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )
|
||||
{
|
||||
long_filename = fatfs_lfn_cache_get(&lfn);
|
||||
|
||||
// Compare names to see if they match
|
||||
if (fatfs_compare_names(long_filename, name_to_find))
|
||||
{
|
||||
memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fatfs_lfn_cache_init(&lfn, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
// Normal Entry, only 8.3 Text
|
||||
if (fatfs_entry_sfn_only(directoryEntry) )
|
||||
{
|
||||
memset(short_filename, 0, sizeof(short_filename));
|
||||
|
||||
// Copy name to string
|
||||
for (i=0; i<8; i++)
|
||||
short_filename[i] = directoryEntry->Name[i];
|
||||
|
||||
// Extension
|
||||
dotRequired = 0;
|
||||
for (i=8; i<11; i++)
|
||||
{
|
||||
short_filename[i+1] = directoryEntry->Name[i];
|
||||
if (directoryEntry->Name[i] != ' ')
|
||||
dotRequired = 1;
|
||||
}
|
||||
|
||||
// Dot only required if extension present
|
||||
if (dotRequired)
|
||||
{
|
||||
// If not . or .. entry
|
||||
if (short_filename[0]!='.')
|
||||
short_filename[8] = '.';
|
||||
else
|
||||
short_filename[8] = ' ';
|
||||
}
|
||||
else
|
||||
short_filename[8] = ' ';
|
||||
|
||||
// Compare names to see if they match
|
||||
if (fatfs_compare_names(short_filename, name_to_find))
|
||||
{
|
||||
memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));
|
||||
return 1;
|
||||
}
|
||||
|
||||
fatfs_lfn_cache_init(&lfn, 0);
|
||||
}
|
||||
} // End of if
|
||||
}
|
||||
else
|
||||
break;
|
||||
} // End of while loop
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
// fatfs_sfn_exists: Check if a short filename exists.
|
||||
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
|
||||
//-------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_sfn_exists(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname)
|
||||
{
|
||||
uint8 item=0;
|
||||
uint16 recordoffset = 0;
|
||||
int x=0;
|
||||
struct fat_dir_entry *directoryEntry;
|
||||
|
||||
// Main cluster following loop
|
||||
while (1)
|
||||
{
|
||||
// Read sector
|
||||
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
|
||||
{
|
||||
// Analyse Sector
|
||||
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Create the multiplier for sector access
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// Overlay directory entry over buffer
|
||||
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// Long File Name Text Found
|
||||
if (fatfs_entry_lfn_text(directoryEntry) )
|
||||
;
|
||||
|
||||
// If Invalid record found delete any long file name information collated
|
||||
else if (fatfs_entry_lfn_invalid(directoryEntry) )
|
||||
;
|
||||
else
|
||||
#endif
|
||||
// Normal Entry, only 8.3 Text
|
||||
if (fatfs_entry_sfn_only(directoryEntry) )
|
||||
{
|
||||
if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)
|
||||
return 1;
|
||||
}
|
||||
} // End of if
|
||||
}
|
||||
else
|
||||
break;
|
||||
} // End of while loop
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-------------------------------------------------------------
|
||||
// fatfs_update_timestamps: Update date/time details
|
||||
//-------------------------------------------------------------
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access)
|
||||
{
|
||||
time_t time_now;
|
||||
struct tm * time_info;
|
||||
uint16 fat_time;
|
||||
uint16 fat_date;
|
||||
|
||||
// Get system time
|
||||
time(&time_now);
|
||||
|
||||
// Convert to local time
|
||||
time_info = localtime(&time_now);
|
||||
|
||||
// Convert time to FAT format
|
||||
fat_time = fatfs_convert_to_fat_time(time_info->tm_hour, time_info->tm_min, time_info->tm_sec);
|
||||
|
||||
// Convert date to FAT format
|
||||
fat_date = fatfs_convert_to_fat_date(time_info->tm_mday, time_info->tm_mon + 1, time_info->tm_year + 1900);
|
||||
|
||||
// Update requested fields
|
||||
if (create)
|
||||
{
|
||||
directoryEntry->CrtTime[1] = fat_time >> 8;
|
||||
directoryEntry->CrtTime[0] = fat_time >> 0;
|
||||
directoryEntry->CrtDate[1] = fat_date >> 8;
|
||||
directoryEntry->CrtDate[0] = fat_date >> 0;
|
||||
}
|
||||
|
||||
if (modify)
|
||||
{
|
||||
directoryEntry->WrtTime[1] = fat_time >> 8;
|
||||
directoryEntry->WrtTime[0] = fat_time >> 0;
|
||||
directoryEntry->WrtDate[1] = fat_date >> 8;
|
||||
directoryEntry->WrtDate[0] = fat_date >> 0;
|
||||
}
|
||||
|
||||
if (access)
|
||||
{
|
||||
directoryEntry->LstAccDate[1] = fat_time >> 8;
|
||||
directoryEntry->LstAccDate[0] = fat_time >> 0;
|
||||
directoryEntry->LstAccDate[1] = fat_date >> 8;
|
||||
directoryEntry->LstAccDate[0] = fat_date >> 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-------------------------------------------------------------
|
||||
// fatfs_update_file_length: Find a SFN entry and update it
|
||||
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
|
||||
//-------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_update_file_length(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength)
|
||||
{
|
||||
uint8 item=0;
|
||||
uint16 recordoffset = 0;
|
||||
int x=0;
|
||||
struct fat_dir_entry *directoryEntry;
|
||||
|
||||
// No write access?
|
||||
if (!fs->disk_io.write_media)
|
||||
return 0;
|
||||
|
||||
// Main cluster following loop
|
||||
while (1)
|
||||
{
|
||||
// Read sector
|
||||
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
|
||||
{
|
||||
// Analyse Sector
|
||||
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Create the multiplier for sector access
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// Overlay directory entry over buffer
|
||||
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// Long File Name Text Found
|
||||
if (fatfs_entry_lfn_text(directoryEntry) )
|
||||
;
|
||||
|
||||
// If Invalid record found delete any long file name information collated
|
||||
else if (fatfs_entry_lfn_invalid(directoryEntry) )
|
||||
;
|
||||
|
||||
// Normal Entry, only 8.3 Text
|
||||
else
|
||||
#endif
|
||||
if (fatfs_entry_sfn_only(directoryEntry) )
|
||||
{
|
||||
if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)
|
||||
{
|
||||
directoryEntry->FileSize = FAT_HTONL(fileLength);
|
||||
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
// Update access / modify time & date
|
||||
fatfs_update_timestamps(directoryEntry, 0, 1, 1);
|
||||
#endif
|
||||
|
||||
// Update sfn entry
|
||||
memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));
|
||||
|
||||
// Write sector back
|
||||
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
}
|
||||
} // End of if
|
||||
}
|
||||
else
|
||||
break;
|
||||
} // End of while loop
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-------------------------------------------------------------
|
||||
// fatfs_mark_file_deleted: Find a SFN entry and mark if as deleted
|
||||
// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY
|
||||
//-------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_mark_file_deleted(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname)
|
||||
{
|
||||
uint8 item=0;
|
||||
uint16 recordoffset = 0;
|
||||
int x=0;
|
||||
struct fat_dir_entry *directoryEntry;
|
||||
|
||||
// No write access?
|
||||
if (!fs->disk_io.write_media)
|
||||
return 0;
|
||||
|
||||
// Main cluster following loop
|
||||
while (1)
|
||||
{
|
||||
// Read sector
|
||||
if (fatfs_sector_reader(ctx, fs, Cluster, x++, 0)) // If sector read was successfull
|
||||
{
|
||||
// Analyse Sector
|
||||
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Create the multiplier for sector access
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// Overlay directory entry over buffer
|
||||
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// Long File Name Text Found
|
||||
if (fatfs_entry_lfn_text(directoryEntry) )
|
||||
;
|
||||
|
||||
// If Invalid record found delete any long file name information collated
|
||||
else if (fatfs_entry_lfn_invalid(directoryEntry) )
|
||||
;
|
||||
|
||||
// Normal Entry, only 8.3 Text
|
||||
else
|
||||
#endif
|
||||
if (fatfs_entry_sfn_only(directoryEntry) )
|
||||
{
|
||||
if (strncmp((const char *)directoryEntry->Name, shortname, 11)==0)
|
||||
{
|
||||
// Mark as deleted
|
||||
directoryEntry->Name[0] = FILE_HEADER_DELETED;
|
||||
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
// Update access / modify time & date
|
||||
fatfs_update_timestamps(directoryEntry, 0, 1, 1);
|
||||
#endif
|
||||
|
||||
// Update sfn entry
|
||||
memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));
|
||||
|
||||
// Write sector back
|
||||
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
}
|
||||
} // End of if
|
||||
}
|
||||
else
|
||||
break;
|
||||
} // End of while loop
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_list_directory_start: Initialise a directory listing procedure
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_DIR_LIST_SUPPORT
|
||||
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster)
|
||||
{
|
||||
dirls->cluster = StartCluster;
|
||||
dirls->sector = 0;
|
||||
dirls->offset = 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_list_directory_next: Get the next entry in the directory.
|
||||
// Returns: 1 = found, 0 = end of listing
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_DIR_LIST_SUPPORT
|
||||
int fatfs_list_directory_next(struct fat_ctx *ctx, struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry)
|
||||
{
|
||||
uint8 i,item;
|
||||
uint16 recordoffset;
|
||||
struct fat_dir_entry *directoryEntry;
|
||||
char *long_filename = NULL;
|
||||
char short_filename[13];
|
||||
struct lfn_cache lfn;
|
||||
int dotRequired = 0;
|
||||
int result = 0;
|
||||
|
||||
// Initialise LFN cache first
|
||||
fatfs_lfn_cache_init(&lfn, 0);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// If data read OK
|
||||
if (fatfs_sector_reader(ctx, fs, dirls->cluster, dirls->sector, 0))
|
||||
{
|
||||
// Maximum of 16 directory entries
|
||||
for (item = dirls->offset; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Increase directory offset
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// Overlay directory entry over buffer
|
||||
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// Long File Name Text Found
|
||||
if ( fatfs_entry_lfn_text(directoryEntry) )
|
||||
fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);
|
||||
|
||||
// If Invalid record found delete any long file name information collated
|
||||
else if ( fatfs_entry_lfn_invalid(directoryEntry) )
|
||||
fatfs_lfn_cache_init(&lfn, 0);
|
||||
|
||||
// Normal SFN Entry and Long text exists
|
||||
else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )
|
||||
{
|
||||
// Get text
|
||||
long_filename = fatfs_lfn_cache_get(&lfn);
|
||||
strncpy(entry->filename, long_filename, FATFS_MAX_LONG_FILENAME-1);
|
||||
|
||||
if (fatfs_entry_is_dir(directoryEntry))
|
||||
entry->is_dir = 1;
|
||||
else
|
||||
entry->is_dir = 0;
|
||||
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
// Get time / dates
|
||||
entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];
|
||||
entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];
|
||||
entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];
|
||||
entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];
|
||||
entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];
|
||||
#endif
|
||||
|
||||
entry->size = FAT_HTONL(directoryEntry->FileSize);
|
||||
entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);
|
||||
|
||||
// Next starting position
|
||||
dirls->offset = item + 1;
|
||||
result = 1;
|
||||
return 1;
|
||||
}
|
||||
// Normal Entry, only 8.3 Text
|
||||
else
|
||||
#endif
|
||||
if ( fatfs_entry_sfn_only(directoryEntry) )
|
||||
{
|
||||
fatfs_lfn_cache_init(&lfn, 0);
|
||||
|
||||
memset(short_filename, 0, sizeof(short_filename));
|
||||
|
||||
// Copy name to string
|
||||
for (i=0; i<8; i++)
|
||||
short_filename[i] = directoryEntry->Name[i];
|
||||
|
||||
// Extension
|
||||
dotRequired = 0;
|
||||
for (i=8; i<11; i++)
|
||||
{
|
||||
short_filename[i+1] = directoryEntry->Name[i];
|
||||
if (directoryEntry->Name[i] != ' ')
|
||||
dotRequired = 1;
|
||||
}
|
||||
|
||||
// Dot only required if extension present
|
||||
if (dotRequired)
|
||||
{
|
||||
// If not . or .. entry
|
||||
if (short_filename[0]!='.')
|
||||
short_filename[8] = '.';
|
||||
else
|
||||
short_filename[8] = ' ';
|
||||
}
|
||||
else
|
||||
short_filename[8] = ' ';
|
||||
|
||||
fatfs_get_sfn_display_name(entry->filename, short_filename);
|
||||
|
||||
if (fatfs_entry_is_dir(directoryEntry))
|
||||
entry->is_dir = 1;
|
||||
else
|
||||
entry->is_dir = 0;
|
||||
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
// Get time / dates
|
||||
entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];
|
||||
entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];
|
||||
entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];
|
||||
entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];
|
||||
entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];
|
||||
#endif
|
||||
|
||||
entry->size = FAT_HTONL(directoryEntry->FileSize);
|
||||
entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);
|
||||
|
||||
// Next starting position
|
||||
dirls->offset = item + 1;
|
||||
result = 1;
|
||||
return 1;
|
||||
}
|
||||
}// end of for
|
||||
|
||||
// If reached end of the dir move onto next sector
|
||||
dirls->sector++;
|
||||
dirls->offset = 0;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
135
kernel/fs/fatfs/fat_access.h
Normal file
135
kernel/fs/fatfs/fat_access.h
Normal file
@ -0,0 +1,135 @@
|
||||
#ifndef __FAT_ACCESS_H__
|
||||
#define __FAT_ACCESS_H__
|
||||
|
||||
#include "fat_defs.h"
|
||||
#include "fat_opts.h"
|
||||
|
||||
struct fat_ctx;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//-----------------------------------------------------------------------------
|
||||
#define FAT_INIT_OK 0
|
||||
#define FAT_INIT_MEDIA_ACCESS_ERROR (-1)
|
||||
#define FAT_INIT_INVALID_SECTOR_SIZE (-2)
|
||||
#define FAT_INIT_INVALID_SIGNATURE (-3)
|
||||
#define FAT_INIT_ENDIAN_ERROR (-4)
|
||||
#define FAT_INIT_WRONG_FILESYS_TYPE (-5)
|
||||
#define FAT_INIT_WRONG_PARTITION_TYPE (-6)
|
||||
#define FAT_INIT_STRUCT_PACKING (-7)
|
||||
|
||||
#define FAT_DIR_ENTRIES_PER_SECTOR (FAT_SECTOR_SIZE / FAT_DIR_ENTRY_SIZE)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Function Pointers
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int (*fn_diskio_read) (struct fat_ctx *ctx, uint32 sector, uint8 *buffer, uint32 sector_count);
|
||||
typedef int (*fn_diskio_write)(struct fat_ctx *ctx, uint32 sector, uint8 *buffer, uint32 sector_count);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures
|
||||
//-----------------------------------------------------------------------------
|
||||
struct disk_if
|
||||
{
|
||||
// User supplied function pointers for disk IO
|
||||
fn_diskio_read read_media;
|
||||
fn_diskio_write write_media;
|
||||
};
|
||||
|
||||
// Forward declaration
|
||||
struct fat_buffer;
|
||||
|
||||
struct fat_buffer
|
||||
{
|
||||
uint8 sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
|
||||
uint32 address;
|
||||
int dirty;
|
||||
uint8 * ptr;
|
||||
|
||||
// Next in chain of sector buffers
|
||||
struct fat_buffer *next;
|
||||
};
|
||||
|
||||
typedef enum eFatType
|
||||
{
|
||||
FAT_TYPE_16,
|
||||
FAT_TYPE_32
|
||||
} tFatType;
|
||||
|
||||
struct fatfs
|
||||
{
|
||||
// Filesystem globals
|
||||
uint8 sectors_per_cluster;
|
||||
uint32 cluster_begin_lba;
|
||||
uint32 rootdir_first_cluster;
|
||||
uint32 rootdir_first_sector;
|
||||
uint32 rootdir_sectors;
|
||||
uint32 fat_begin_lba;
|
||||
uint16 fs_info_sector;
|
||||
uint32 lba_begin;
|
||||
uint32 fat_sectors;
|
||||
uint32 next_free_cluster;
|
||||
uint16 root_entry_count;
|
||||
uint16 reserved_sectors;
|
||||
uint8 num_of_fats;
|
||||
tFatType fat_type;
|
||||
|
||||
// Disk/Media API
|
||||
struct disk_if disk_io;
|
||||
|
||||
// [Optional] Thread Safety
|
||||
void (*fl_lock)(void);
|
||||
void (*fl_unlock)(void);
|
||||
|
||||
// Working buffer
|
||||
struct fat_buffer currentsector;
|
||||
|
||||
// FAT Buffer
|
||||
struct fat_buffer *fat_buffer_head;
|
||||
struct fat_buffer fat_buffers[FAT_BUFFERS];
|
||||
};
|
||||
|
||||
struct fs_dir_list_status
|
||||
{
|
||||
uint32 sector;
|
||||
uint32 cluster;
|
||||
uint8 offset;
|
||||
};
|
||||
|
||||
struct fs_dir_ent
|
||||
{
|
||||
char filename[FATFS_MAX_LONG_FILENAME];
|
||||
uint8 is_dir;
|
||||
uint32 cluster;
|
||||
uint32 size;
|
||||
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
uint16 access_date;
|
||||
uint16 write_time;
|
||||
uint16 write_date;
|
||||
uint16 create_date;
|
||||
uint16 create_time;
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_init(struct fat_ctx *ctx, struct fatfs *fs);
|
||||
uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number);
|
||||
int fatfs_sector_reader(struct fat_ctx *ctx, struct fatfs *fs, uint32 Startcluster, uint32 offset, uint8 *target);
|
||||
int fatfs_sector_read(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
|
||||
int fatfs_sector_write(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
|
||||
int fatfs_read_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
|
||||
int fatfs_write_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
|
||||
void fatfs_show_details(struct fatfs *fs);
|
||||
uint32 fatfs_get_root_cluster(struct fatfs *fs);
|
||||
uint32 fatfs_get_file_entry(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *nametofind, struct fat_dir_entry *sfEntry);
|
||||
int fatfs_sfn_exists(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname);
|
||||
int fatfs_update_file_length(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength);
|
||||
int fatfs_mark_file_deleted(struct fat_ctx *ctx, struct fatfs *fs, uint32 Cluster, char *shortname);
|
||||
void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster);
|
||||
int fatfs_list_directory_next(struct fat_ctx *ctx, struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry);
|
||||
int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access);
|
||||
|
||||
#endif
|
||||
91
kernel/fs/fatfs/fat_cache.c
Normal file
91
kernel/fs/fatfs/fat_cache.c
Normal file
@ -0,0 +1,91 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include "fat_cache.h"
|
||||
|
||||
// Per file cluster chain caching used to improve performance.
|
||||
// This does not have to be enabled for architectures with low
|
||||
// memory space.
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_cache_init:
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file)
|
||||
{
|
||||
#ifdef FAT_CLUSTER_CACHE_ENTRIES
|
||||
int i;
|
||||
|
||||
for (i=0;i<FAT_CLUSTER_CACHE_ENTRIES;i++)
|
||||
{
|
||||
file->cluster_cache_idx[i] = 0xFFFFFFFF; // Not used
|
||||
file->cluster_cache_data[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_cache_get_next_cluster:
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster)
|
||||
{
|
||||
#ifdef FAT_CLUSTER_CACHE_ENTRIES
|
||||
uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
|
||||
|
||||
if (file->cluster_cache_idx[slot] == clusterIdx)
|
||||
{
|
||||
*pNextCluster = file->cluster_cache_data[slot];
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_cache_set_next_cluster:
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster)
|
||||
{
|
||||
#ifdef FAT_CLUSTER_CACHE_ENTRIES
|
||||
uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
|
||||
|
||||
if (file->cluster_cache_idx[slot] == clusterIdx)
|
||||
file->cluster_cache_data[slot] = nextCluster;
|
||||
else
|
||||
{
|
||||
file->cluster_cache_idx[slot] = clusterIdx;
|
||||
file->cluster_cache_data[slot] = nextCluster;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
13
kernel/fs/fatfs/fat_cache.h
Normal file
13
kernel/fs/fatfs/fat_cache.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __FAT_CACHE_H__
|
||||
#define __FAT_CACHE_H__
|
||||
|
||||
#include "fat_filelib.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_cache_init(struct fatfs *fs, FL_FILE *file);
|
||||
int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster);
|
||||
int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster);
|
||||
|
||||
#endif
|
||||
17
kernel/fs/fatfs/fat_context.h
Normal file
17
kernel/fs/fatfs/fat_context.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef FAT_CONTEXT_H_
|
||||
#define FAT_CONTEXT_H_
|
||||
|
||||
#include "fat_defs.h"
|
||||
#include "fat_filelib.h"
|
||||
|
||||
struct fat_ctx {
|
||||
FL_FILE _files[FATFS_MAX_OPEN_FILES];
|
||||
int _filelib_init;
|
||||
int _filelib_valid;
|
||||
struct fatfs _fs;
|
||||
struct fat_list _open_file_list;
|
||||
struct fat_list _free_file_list;
|
||||
void *extra;
|
||||
};
|
||||
|
||||
#endif // FAT_CONTEXT_H_
|
||||
128
kernel/fs/fatfs/fat_defs.h
Normal file
128
kernel/fs/fatfs/fat_defs.h
Normal file
@ -0,0 +1,128 @@
|
||||
#ifndef __FAT_DEFS_H__
|
||||
#define __FAT_DEFS_H__
|
||||
|
||||
#include "fat_opts.h"
|
||||
#include "fat_types.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT32 Offsets
|
||||
// Name Offset
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Boot Sector
|
||||
#define BS_JMPBOOT 0 // Length = 3
|
||||
#define BS_OEMNAME 3 // Length = 8
|
||||
#define BPB_BYTSPERSEC 11 // Length = 2
|
||||
#define BPB_SECPERCLUS 13 // Length = 1
|
||||
#define BPB_RSVDSECCNT 14 // Length = 2
|
||||
#define BPB_NUMFATS 16 // Length = 1
|
||||
#define BPB_ROOTENTCNT 17 // Length = 2
|
||||
#define BPB_TOTSEC16 19 // Length = 2
|
||||
#define BPB_MEDIA 21 // Length = 1
|
||||
#define BPB_FATSZ16 22 // Length = 2
|
||||
#define BPB_SECPERTRK 24 // Length = 2
|
||||
#define BPB_NUMHEADS 26 // Length = 2
|
||||
#define BPB_HIDDSEC 28 // Length = 4
|
||||
#define BPB_TOTSEC32 32 // Length = 4
|
||||
|
||||
// FAT 12/16
|
||||
#define BS_FAT_DRVNUM 36 // Length = 1
|
||||
#define BS_FAT_BOOTSIG 38 // Length = 1
|
||||
#define BS_FAT_VOLID 39 // Length = 4
|
||||
#define BS_FAT_VOLLAB 43 // Length = 11
|
||||
#define BS_FAT_FILSYSTYPE 54 // Length = 8
|
||||
|
||||
// FAT 32
|
||||
#define BPB_FAT32_FATSZ32 36 // Length = 4
|
||||
#define BPB_FAT32_EXTFLAGS 40 // Length = 2
|
||||
#define BPB_FAT32_FSVER 42 // Length = 2
|
||||
#define BPB_FAT32_ROOTCLUS 44 // Length = 4
|
||||
#define BPB_FAT32_FSINFO 48 // Length = 2
|
||||
#define BPB_FAT32_BKBOOTSEC 50 // Length = 2
|
||||
#define BS_FAT32_DRVNUM 64 // Length = 1
|
||||
#define BS_FAT32_BOOTSIG 66 // Length = 1
|
||||
#define BS_FAT32_VOLID 67 // Length = 4
|
||||
#define BS_FAT32_VOLLAB 71 // Length = 11
|
||||
#define BS_FAT32_FILSYSTYPE 82 // Length = 8
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT Types
|
||||
//-----------------------------------------------------------------------------
|
||||
#define FAT_TYPE_FAT12 1
|
||||
#define FAT_TYPE_FAT16 2
|
||||
#define FAT_TYPE_FAT32 3
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT32 Specific Statics
|
||||
//-----------------------------------------------------------------------------
|
||||
#define SIGNATURE_POSITION 510
|
||||
#define SIGNATURE_VALUE 0xAA55
|
||||
#define PARTITION1_TYPECODE_LOCATION 450
|
||||
#define FAT32_TYPECODE1 0x0B
|
||||
#define FAT32_TYPECODE2 0x0C
|
||||
#define PARTITION1_LBA_BEGIN_LOCATION 454
|
||||
#define PARTITION1_SIZE_LOCATION 458
|
||||
|
||||
#define FAT_DIR_ENTRY_SIZE 32
|
||||
#define FAT_SFN_SIZE_FULL 11
|
||||
#define FAT_SFN_SIZE_PARTIAL 8
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT32 File Attributes and Types
|
||||
//-----------------------------------------------------------------------------
|
||||
#define FILE_ATTR_READ_ONLY 0x01
|
||||
#define FILE_ATTR_HIDDEN 0x02
|
||||
#define FILE_ATTR_SYSTEM 0x04
|
||||
#define FILE_ATTR_SYSHID 0x06
|
||||
#define FILE_ATTR_VOLUME_ID 0x08
|
||||
#define FILE_ATTR_DIRECTORY 0x10
|
||||
#define FILE_ATTR_ARCHIVE 0x20
|
||||
#define FILE_ATTR_LFN_TEXT 0x0F
|
||||
#define FILE_HEADER_BLANK 0x00
|
||||
#define FILE_HEADER_DELETED 0xE5
|
||||
#define FILE_TYPE_DIR 0x10
|
||||
#define FILE_TYPE_FILE 0x20
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Time / Date details
|
||||
//-----------------------------------------------------------------------------
|
||||
#define FAT_TIME_HOURS_SHIFT 11
|
||||
#define FAT_TIME_HOURS_MASK 0x1F
|
||||
#define FAT_TIME_MINUTES_SHIFT 5
|
||||
#define FAT_TIME_MINUTES_MASK 0x3F
|
||||
#define FAT_TIME_SECONDS_SHIFT 0
|
||||
#define FAT_TIME_SECONDS_MASK 0x1F
|
||||
#define FAT_TIME_SECONDS_SCALE 2
|
||||
#define FAT_DATE_YEAR_SHIFT 9
|
||||
#define FAT_DATE_YEAR_MASK 0x7F
|
||||
#define FAT_DATE_MONTH_SHIFT 5
|
||||
#define FAT_DATE_MONTH_MASK 0xF
|
||||
#define FAT_DATE_DAY_SHIFT 0
|
||||
#define FAT_DATE_DAY_MASK 0x1F
|
||||
#define FAT_DATE_YEAR_OFFSET 1980
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Other Defines
|
||||
//-----------------------------------------------------------------------------
|
||||
#define FAT32_LAST_CLUSTER 0xFFFFFFFF
|
||||
#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
|
||||
|
||||
STRUCT_PACK_BEGIN
|
||||
struct fat_dir_entry STRUCT_PACK
|
||||
{
|
||||
uint8 Name[11];
|
||||
uint8 Attr;
|
||||
uint8 NTRes;
|
||||
uint8 CrtTimeTenth;
|
||||
uint8 CrtTime[2];
|
||||
uint8 CrtDate[2];
|
||||
uint8 LstAccDate[2];
|
||||
uint16 FstClusHI;
|
||||
uint8 WrtTime[2];
|
||||
uint8 WrtDate[2];
|
||||
uint16 FstClusLO;
|
||||
uint32 FileSize;
|
||||
} STRUCT_PACKED;
|
||||
STRUCT_PACK_END
|
||||
|
||||
#endif
|
||||
1595
kernel/fs/fatfs/fat_filelib.c
Normal file
1595
kernel/fs/fatfs/fat_filelib.c
Normal file
File diff suppressed because it is too large
Load Diff
148
kernel/fs/fatfs/fat_filelib.h
Normal file
148
kernel/fs/fatfs/fat_filelib.h
Normal file
@ -0,0 +1,148 @@
|
||||
#ifndef __FAT_FILELIB_H__
|
||||
#define __FAT_FILELIB_H__
|
||||
|
||||
#include "fat_opts.h"
|
||||
#include "fat_access.h"
|
||||
#include "fat_list.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef SEEK_CUR
|
||||
#define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_END
|
||||
#define SEEK_END 2
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures
|
||||
//-----------------------------------------------------------------------------
|
||||
struct sFL_FILE;
|
||||
|
||||
struct fat_ctx;
|
||||
|
||||
struct cluster_lookup
|
||||
{
|
||||
uint32 ClusterIdx;
|
||||
uint32 CurrentCluster;
|
||||
};
|
||||
|
||||
typedef struct sFL_FILE
|
||||
{
|
||||
uint32 parentcluster;
|
||||
uint32 startcluster;
|
||||
uint32 bytenum;
|
||||
uint32 filelength;
|
||||
int filelength_changed;
|
||||
char path[FATFS_MAX_LONG_FILENAME];
|
||||
char filename[FATFS_MAX_LONG_FILENAME];
|
||||
uint8 shortfilename[11];
|
||||
|
||||
#ifdef FAT_CLUSTER_CACHE_ENTRIES
|
||||
uint32 cluster_cache_idx[FAT_CLUSTER_CACHE_ENTRIES];
|
||||
uint32 cluster_cache_data[FAT_CLUSTER_CACHE_ENTRIES];
|
||||
#endif
|
||||
|
||||
// Cluster Lookup
|
||||
struct cluster_lookup last_fat_lookup;
|
||||
|
||||
// Read/Write sector buffer
|
||||
uint8 file_data_sector[FAT_SECTOR_SIZE];
|
||||
uint32 file_data_address;
|
||||
int file_data_dirty;
|
||||
|
||||
// File fopen flags
|
||||
uint8 flags;
|
||||
#define FILE_READ (1 << 0)
|
||||
#define FILE_WRITE (1 << 1)
|
||||
#define FILE_APPEND (1 << 2)
|
||||
#define FILE_BINARY (1 << 3)
|
||||
#define FILE_ERASE (1 << 4)
|
||||
#define FILE_CREATE (1 << 5)
|
||||
|
||||
struct fat_node list_node;
|
||||
} FL_FILE;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// External
|
||||
void fl_init(struct fat_ctx *ctx);
|
||||
void fl_attach_locks(struct fat_ctx *ctx, void (*lock)(void), void (*unlock)(void));
|
||||
int fl_attach_media(struct fat_ctx *ctx, fn_diskio_read rd, fn_diskio_write wr);
|
||||
void fl_shutdown(struct fat_ctx *ctx);
|
||||
|
||||
// Standard API
|
||||
void* fl_fopen(struct fat_ctx *ctx, const char *path, const char *modifiers);
|
||||
void fl_fclose(struct fat_ctx *ctx, void *file);
|
||||
int fl_fflush(struct fat_ctx *ctx, void *file);
|
||||
int fl_fgetc(struct fat_ctx *ctx, void *file);
|
||||
char * fl_fgets(struct fat_ctx *ctx, char *s, int n, void *f);
|
||||
int fl_fputc(struct fat_ctx *ctx, int c, void *file);
|
||||
int fl_fputs(struct fat_ctx *ctx, const char * str, void *file);
|
||||
int fl_fwrite(struct fat_ctx *ctx, const void * data, int size, int count, void *file );
|
||||
int fl_fread(struct fat_ctx *ctx, void * data, int size, int count, void *file );
|
||||
int fl_fseek(struct fat_ctx *ctx, void *file , long offset , int origin );
|
||||
int fl_fgetpos(struct fat_ctx *ctx, void *file , uint32 * position);
|
||||
long fl_ftell(struct fat_ctx *ctx, void *f);
|
||||
int fl_feof(struct fat_ctx *ctx, void *f);
|
||||
int fl_remove(struct fat_ctx *ctx, const char * filename);
|
||||
|
||||
// Equivelant dirent.h
|
||||
typedef struct fs_dir_list_status FL_DIR;
|
||||
typedef struct fs_dir_ent fl_dirent;
|
||||
|
||||
FL_DIR* fl_opendir(struct fat_ctx *ctx, const char* path, FL_DIR *dir);
|
||||
int fl_readdir(struct fat_ctx *ctx, FL_DIR *dirls, fl_dirent *entry);
|
||||
int fl_closedir(struct fat_ctx *ctx, FL_DIR* dir);
|
||||
|
||||
// Extensions
|
||||
void fl_listdirectory(struct fat_ctx *ctx, const char *path);
|
||||
int fl_createdirectory(struct fat_ctx *ctx, const char *path);
|
||||
int fl_is_dir(struct fat_ctx *ctx, const char *path);
|
||||
|
||||
int fl_format(struct fat_ctx *ctx, uint32 volume_sectors, const char *name);
|
||||
|
||||
// Test hooks
|
||||
#ifdef FATFS_INC_TEST_HOOKS
|
||||
struct fatfs* fl_get_fs(struct fat_ctx *ctx);
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stdio file I/O names
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef USE_FILELIB_STDIO_COMPAT_NAMES
|
||||
|
||||
#define FILE FL_FILE
|
||||
|
||||
#define fopen(a,b) fl_fopen(a, b)
|
||||
#define fclose(a) fl_fclose(a)
|
||||
#define fflush(a) fl_fflush(a)
|
||||
#define fgetc(a) fl_fgetc(a)
|
||||
#define fgets(a,b,c) fl_fgets(a, b, c)
|
||||
#define fputc(a,b) fl_fputc(a, b)
|
||||
#define fputs(a,b) fl_fputs(a, b)
|
||||
#define fwrite(a,b,c,d) fl_fwrite(a, b, c, d)
|
||||
#define fread(a,b,c,d) fl_fread(a, b, c, d)
|
||||
#define fseek(a,b,c) fl_fseek(a, b, c)
|
||||
#define fgetpos(a,b) fl_fgetpos(a, b)
|
||||
#define ftell(a) fl_ftell(a)
|
||||
#define feof(a) fl_feof(a)
|
||||
#define remove(a) fl_remove(a)
|
||||
#define mkdir(a) fl_createdirectory(a)
|
||||
#define rmdir(a) 0
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
532
kernel/fs/fatfs/fat_format.c
Normal file
532
kernel/fs/fatfs/fat_format.c
Normal file
@ -0,0 +1,532 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include "fat_defs.h"
|
||||
#include "fat_access.h"
|
||||
#include "fat_table.h"
|
||||
#include "fat_write.h"
|
||||
#include "fat_string.h"
|
||||
#include "fat_misc.h"
|
||||
#include "fat_format.h"
|
||||
|
||||
#if FATFS_INC_FORMAT_SUPPORT
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tables
|
||||
//-----------------------------------------------------------------------------
|
||||
struct sec_per_clus_table
|
||||
{
|
||||
uint32 sectors;
|
||||
uint8 sectors_per_cluster;
|
||||
};
|
||||
|
||||
struct sec_per_clus_table _cluster_size_table16[] =
|
||||
{
|
||||
{ 32680, 2}, // 16MB - 1K
|
||||
{ 262144, 4}, // 128MB - 2K
|
||||
{ 524288, 8}, // 256MB - 4K
|
||||
{ 1048576, 16}, // 512MB - 8K
|
||||
{ 2097152, 32}, // 1GB - 16K
|
||||
{ 4194304, 64}, // 2GB - 32K
|
||||
{ 8388608, 128},// 2GB - 64K [Warning only supported by Windows XP onwards]
|
||||
{ 0 , 0 } // Invalid
|
||||
};
|
||||
|
||||
struct sec_per_clus_table _cluster_size_table32[] =
|
||||
{
|
||||
{ 532480, 1}, // 260MB - 512b
|
||||
{ 16777216, 8}, // 8GB - 4K
|
||||
{ 33554432, 16}, // 16GB - 8K
|
||||
{ 67108864, 32}, // 32GB - 16K
|
||||
{ 0xFFFFFFFF, 64},// >32GB - 32K
|
||||
{ 0 , 0 } // Invalid
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_calc_cluster_size: Calculate what cluster size should be used
|
||||
//-----------------------------------------------------------------------------
|
||||
static uint8 fatfs_calc_cluster_size(uint32 sectors, int is_fat32)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!is_fat32)
|
||||
{
|
||||
for (i=0; _cluster_size_table16[i].sectors_per_cluster != 0;i++)
|
||||
if (sectors <= _cluster_size_table16[i].sectors)
|
||||
return _cluster_size_table16[i].sectors_per_cluster;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; _cluster_size_table32[i].sectors_per_cluster != 0;i++)
|
||||
if (sectors <= _cluster_size_table32[i].sectors)
|
||||
return _cluster_size_table32[i].sectors_per_cluster;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_erase_sectors: Erase a number of sectors
|
||||
//-----------------------------------------------------------------------------
|
||||
static int fatfs_erase_sectors(struct fat_ctx *ctx, struct fatfs *fs, uint32 lba, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Zero sector first
|
||||
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
|
||||
|
||||
for (i=0;i<count;i++)
|
||||
if (!fs->disk_io.write_media(ctx, lba + i, fs->currentsector.sector, 1))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_create_boot_sector: Create the boot sector
|
||||
//-----------------------------------------------------------------------------
|
||||
static int fatfs_create_boot_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 boot_sector_lba, uint32 vol_sectors, const char *name, int is_fat32)
|
||||
{
|
||||
uint32 total_clusters;
|
||||
int i;
|
||||
|
||||
// Zero sector initially
|
||||
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
|
||||
|
||||
// OEM Name & Jump Code
|
||||
fs->currentsector.sector[0] = 0xEB;
|
||||
fs->currentsector.sector[1] = 0x3C;
|
||||
fs->currentsector.sector[2] = 0x90;
|
||||
fs->currentsector.sector[3] = 0x4D;
|
||||
fs->currentsector.sector[4] = 0x53;
|
||||
fs->currentsector.sector[5] = 0x44;
|
||||
fs->currentsector.sector[6] = 0x4F;
|
||||
fs->currentsector.sector[7] = 0x53;
|
||||
fs->currentsector.sector[8] = 0x35;
|
||||
fs->currentsector.sector[9] = 0x2E;
|
||||
fs->currentsector.sector[10] = 0x30;
|
||||
|
||||
// Bytes per sector
|
||||
fs->currentsector.sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
|
||||
fs->currentsector.sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
|
||||
|
||||
// Get sectors per cluster size for the disk
|
||||
fs->sectors_per_cluster = fatfs_calc_cluster_size(vol_sectors, is_fat32);
|
||||
if (!fs->sectors_per_cluster)
|
||||
return 0; // Invalid disk size
|
||||
|
||||
// Sectors per cluster
|
||||
fs->currentsector.sector[13] = fs->sectors_per_cluster;
|
||||
|
||||
// Reserved Sectors
|
||||
if (!is_fat32)
|
||||
fs->reserved_sectors = 8;
|
||||
else
|
||||
fs->reserved_sectors = 32;
|
||||
fs->currentsector.sector[14] = (fs->reserved_sectors >> 0) & 0xFF;
|
||||
fs->currentsector.sector[15] = (fs->reserved_sectors >> 8) & 0xFF;
|
||||
|
||||
// Number of FATS
|
||||
fs->num_of_fats = 2;
|
||||
fs->currentsector.sector[16] = fs->num_of_fats;
|
||||
|
||||
// Max entries in root dir (FAT16 only)
|
||||
if (!is_fat32)
|
||||
{
|
||||
fs->root_entry_count = 512;
|
||||
fs->currentsector.sector[17] = (fs->root_entry_count >> 0) & 0xFF;
|
||||
fs->currentsector.sector[18] = (fs->root_entry_count >> 8) & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
fs->root_entry_count = 0;
|
||||
fs->currentsector.sector[17] = 0;
|
||||
fs->currentsector.sector[18] = 0;
|
||||
}
|
||||
|
||||
// [FAT16] Total sectors (use FAT32 count instead)
|
||||
fs->currentsector.sector[19] = 0x00;
|
||||
fs->currentsector.sector[20] = 0x00;
|
||||
|
||||
// Media type
|
||||
fs->currentsector.sector[21] = 0xF8;
|
||||
|
||||
|
||||
// FAT16 BS Details
|
||||
if (!is_fat32)
|
||||
{
|
||||
// Count of sectors used by the FAT table (FAT16 only)
|
||||
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
|
||||
fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/2)) + 1;
|
||||
fs->currentsector.sector[22] = (uint8)((fs->fat_sectors >> 0) & 0xFF);
|
||||
fs->currentsector.sector[23] = (uint8)((fs->fat_sectors >> 8) & 0xFF);
|
||||
|
||||
// Sectors per track
|
||||
fs->currentsector.sector[24] = 0x00;
|
||||
fs->currentsector.sector[25] = 0x00;
|
||||
|
||||
// Heads
|
||||
fs->currentsector.sector[26] = 0x00;
|
||||
fs->currentsector.sector[27] = 0x00;
|
||||
|
||||
// Hidden sectors
|
||||
fs->currentsector.sector[28] = 0x20;
|
||||
fs->currentsector.sector[29] = 0x00;
|
||||
fs->currentsector.sector[30] = 0x00;
|
||||
fs->currentsector.sector[31] = 0x00;
|
||||
|
||||
// Total sectors for this volume
|
||||
fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
|
||||
fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
|
||||
fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
|
||||
fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
|
||||
|
||||
// Drive number
|
||||
fs->currentsector.sector[36] = 0x00;
|
||||
|
||||
// Reserved
|
||||
fs->currentsector.sector[37] = 0x00;
|
||||
|
||||
// Boot signature
|
||||
fs->currentsector.sector[38] = 0x29;
|
||||
|
||||
// Volume ID
|
||||
fs->currentsector.sector[39] = 0x12;
|
||||
fs->currentsector.sector[40] = 0x34;
|
||||
fs->currentsector.sector[41] = 0x56;
|
||||
fs->currentsector.sector[42] = 0x78;
|
||||
|
||||
// Volume name
|
||||
for (i=0;i<11;i++)
|
||||
{
|
||||
if (i < (int)strlen(name))
|
||||
fs->currentsector.sector[i+43] = name[i];
|
||||
else
|
||||
fs->currentsector.sector[i+43] = ' ';
|
||||
}
|
||||
|
||||
// File sys type
|
||||
fs->currentsector.sector[54] = 'F';
|
||||
fs->currentsector.sector[55] = 'A';
|
||||
fs->currentsector.sector[56] = 'T';
|
||||
fs->currentsector.sector[57] = '1';
|
||||
fs->currentsector.sector[58] = '6';
|
||||
fs->currentsector.sector[59] = ' ';
|
||||
fs->currentsector.sector[60] = ' ';
|
||||
fs->currentsector.sector[61] = ' ';
|
||||
|
||||
// Signature
|
||||
fs->currentsector.sector[510] = 0x55;
|
||||
fs->currentsector.sector[511] = 0xAA;
|
||||
}
|
||||
// FAT32 BS Details
|
||||
else
|
||||
{
|
||||
// Count of sectors used by the FAT table (FAT16 only)
|
||||
fs->currentsector.sector[22] = 0;
|
||||
fs->currentsector.sector[23] = 0;
|
||||
|
||||
// Sectors per track (default)
|
||||
fs->currentsector.sector[24] = 0x3F;
|
||||
fs->currentsector.sector[25] = 0x00;
|
||||
|
||||
// Heads (default)
|
||||
fs->currentsector.sector[26] = 0xFF;
|
||||
fs->currentsector.sector[27] = 0x00;
|
||||
|
||||
// Hidden sectors
|
||||
fs->currentsector.sector[28] = 0x00;
|
||||
fs->currentsector.sector[29] = 0x00;
|
||||
fs->currentsector.sector[30] = 0x00;
|
||||
fs->currentsector.sector[31] = 0x00;
|
||||
|
||||
// Total sectors for this volume
|
||||
fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
|
||||
fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
|
||||
fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
|
||||
fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
|
||||
|
||||
total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
|
||||
fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/4)) + 1;
|
||||
|
||||
// BPB_FATSz32
|
||||
fs->currentsector.sector[36] = (uint8)((fs->fat_sectors>>0)&0xFF);
|
||||
fs->currentsector.sector[37] = (uint8)((fs->fat_sectors>>8)&0xFF);
|
||||
fs->currentsector.sector[38] = (uint8)((fs->fat_sectors>>16)&0xFF);
|
||||
fs->currentsector.sector[39] = (uint8)((fs->fat_sectors>>24)&0xFF);
|
||||
|
||||
// BPB_ExtFlags
|
||||
fs->currentsector.sector[40] = 0;
|
||||
fs->currentsector.sector[41] = 0;
|
||||
|
||||
// BPB_FSVer
|
||||
fs->currentsector.sector[42] = 0;
|
||||
fs->currentsector.sector[43] = 0;
|
||||
|
||||
// BPB_RootClus
|
||||
fs->currentsector.sector[44] = (uint8)((fs->rootdir_first_cluster>>0)&0xFF);
|
||||
fs->currentsector.sector[45] = (uint8)((fs->rootdir_first_cluster>>8)&0xFF);
|
||||
fs->currentsector.sector[46] = (uint8)((fs->rootdir_first_cluster>>16)&0xFF);
|
||||
fs->currentsector.sector[47] = (uint8)((fs->rootdir_first_cluster>>24)&0xFF);
|
||||
|
||||
// BPB_FSInfo
|
||||
fs->currentsector.sector[48] = (uint8)((fs->fs_info_sector>>0)&0xFF);
|
||||
fs->currentsector.sector[49] = (uint8)((fs->fs_info_sector>>8)&0xFF);
|
||||
|
||||
// BPB_BkBootSec
|
||||
fs->currentsector.sector[50] = 6;
|
||||
fs->currentsector.sector[51] = 0;
|
||||
|
||||
// Drive number
|
||||
fs->currentsector.sector[64] = 0x00;
|
||||
|
||||
// Boot signature
|
||||
fs->currentsector.sector[66] = 0x29;
|
||||
|
||||
// Volume ID
|
||||
fs->currentsector.sector[67] = 0x12;
|
||||
fs->currentsector.sector[68] = 0x34;
|
||||
fs->currentsector.sector[69] = 0x56;
|
||||
fs->currentsector.sector[70] = 0x78;
|
||||
|
||||
// Volume name
|
||||
for (i=0;i<11;i++)
|
||||
{
|
||||
if (i < (int)strlen(name))
|
||||
fs->currentsector.sector[i+71] = name[i];
|
||||
else
|
||||
fs->currentsector.sector[i+71] = ' ';
|
||||
}
|
||||
|
||||
// File sys type
|
||||
fs->currentsector.sector[82] = 'F';
|
||||
fs->currentsector.sector[83] = 'A';
|
||||
fs->currentsector.sector[84] = 'T';
|
||||
fs->currentsector.sector[85] = '3';
|
||||
fs->currentsector.sector[86] = '2';
|
||||
fs->currentsector.sector[87] = ' ';
|
||||
fs->currentsector.sector[88] = ' ';
|
||||
fs->currentsector.sector[89] = ' ';
|
||||
|
||||
// Signature
|
||||
fs->currentsector.sector[510] = 0x55;
|
||||
fs->currentsector.sector[511] = 0xAA;
|
||||
}
|
||||
|
||||
if (fs->disk_io.write_media(ctx, boot_sector_lba, fs->currentsector.sector, 1))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_create_fsinfo_sector: Create the FSInfo sector (FAT32)
|
||||
//-----------------------------------------------------------------------------
|
||||
static int fatfs_create_fsinfo_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 sector_lba)
|
||||
{
|
||||
// Zero sector initially
|
||||
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
|
||||
|
||||
// FSI_LeadSig
|
||||
fs->currentsector.sector[0] = 0x52;
|
||||
fs->currentsector.sector[1] = 0x52;
|
||||
fs->currentsector.sector[2] = 0x61;
|
||||
fs->currentsector.sector[3] = 0x41;
|
||||
|
||||
// FSI_StrucSig
|
||||
fs->currentsector.sector[484] = 0x72;
|
||||
fs->currentsector.sector[485] = 0x72;
|
||||
fs->currentsector.sector[486] = 0x41;
|
||||
fs->currentsector.sector[487] = 0x61;
|
||||
|
||||
// FSI_Free_Count
|
||||
fs->currentsector.sector[488] = 0xFF;
|
||||
fs->currentsector.sector[489] = 0xFF;
|
||||
fs->currentsector.sector[490] = 0xFF;
|
||||
fs->currentsector.sector[491] = 0xFF;
|
||||
|
||||
// FSI_Nxt_Free
|
||||
fs->currentsector.sector[492] = 0xFF;
|
||||
fs->currentsector.sector[493] = 0xFF;
|
||||
fs->currentsector.sector[494] = 0xFF;
|
||||
fs->currentsector.sector[495] = 0xFF;
|
||||
|
||||
// Signature
|
||||
fs->currentsector.sector[510] = 0x55;
|
||||
fs->currentsector.sector[511] = 0xAA;
|
||||
|
||||
if (fs->disk_io.write_media(ctx, sector_lba, fs->currentsector.sector, 1))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_erase_fat: Erase FAT table using fs details in fs struct
|
||||
//-----------------------------------------------------------------------------
|
||||
static int fatfs_erase_fat(struct fat_ctx *ctx, struct fatfs *fs, int is_fat32)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
// Zero sector initially
|
||||
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
|
||||
|
||||
// Initialise default allocate / reserved clusters
|
||||
if (!is_fat32)
|
||||
{
|
||||
SET_16BIT_WORD(fs->currentsector.sector, 0, 0xFFF8);
|
||||
SET_16BIT_WORD(fs->currentsector.sector, 2, 0xFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_32BIT_WORD(fs->currentsector.sector, 0, 0x0FFFFFF8);
|
||||
SET_32BIT_WORD(fs->currentsector.sector, 4, 0xFFFFFFFF);
|
||||
SET_32BIT_WORD(fs->currentsector.sector, 8, 0x0FFFFFFF);
|
||||
}
|
||||
|
||||
if (!fs->disk_io.write_media(ctx, fs->fat_begin_lba + 0, fs->currentsector.sector, 1))
|
||||
return 0;
|
||||
|
||||
// Zero remaining FAT sectors
|
||||
memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
|
||||
for (i=1;i<fs->fat_sectors*fs->num_of_fats;i++)
|
||||
if (!fs->disk_io.write_media(ctx, fs->fat_begin_lba + i, fs->currentsector.sector, 1))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_format_fat16: Format a FAT16 partition
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_format_fat16(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name)
|
||||
{
|
||||
fs->currentsector.address = FAT32_INVALID_CLUSTER;
|
||||
fs->currentsector.dirty = 0;
|
||||
|
||||
fs->next_free_cluster = 0; // Invalid
|
||||
|
||||
fatfs_fat_init(fs);
|
||||
|
||||
// Make sure we have read + write functions
|
||||
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
|
||||
return FAT_INIT_MEDIA_ACCESS_ERROR;
|
||||
|
||||
// Volume is FAT16
|
||||
fs->fat_type = FAT_TYPE_16;
|
||||
|
||||
// Not valid for FAT16
|
||||
fs->fs_info_sector = 0;
|
||||
fs->rootdir_first_cluster = 0;
|
||||
|
||||
// Sector 0: Boot sector
|
||||
// NOTE: We don't need an MBR, it is a waste of a good sector!
|
||||
fs->lba_begin = 0;
|
||||
if (!fatfs_create_boot_sector(ctx, fs, fs->lba_begin, volume_sectors, name, 0))
|
||||
return 0;
|
||||
|
||||
// For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
|
||||
fs->rootdir_first_sector = fs->reserved_sectors + (fs->num_of_fats * fs->fat_sectors);
|
||||
fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
|
||||
|
||||
// First FAT LBA address
|
||||
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
|
||||
|
||||
// The address of the first data cluster on this volume
|
||||
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
|
||||
|
||||
// Initialise FAT sectors
|
||||
if (!fatfs_erase_fat(ctx, fs, 0))
|
||||
return 0;
|
||||
|
||||
// Erase Root directory
|
||||
if (!fatfs_erase_sectors(ctx, fs, fs->lba_begin + fs->rootdir_first_sector, fs->rootdir_sectors))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_format_fat32: Format a FAT32 partition
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_format_fat32(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name)
|
||||
{
|
||||
fs->currentsector.address = FAT32_INVALID_CLUSTER;
|
||||
fs->currentsector.dirty = 0;
|
||||
|
||||
fs->next_free_cluster = 0; // Invalid
|
||||
|
||||
fatfs_fat_init(fs);
|
||||
|
||||
// Make sure we have read + write functions
|
||||
if (!fs->disk_io.read_media || !fs->disk_io.write_media)
|
||||
return FAT_INIT_MEDIA_ACCESS_ERROR;
|
||||
|
||||
// Volume is FAT32
|
||||
fs->fat_type = FAT_TYPE_32;
|
||||
|
||||
// Basic defaults for normal FAT32 partitions
|
||||
fs->fs_info_sector = 1;
|
||||
fs->rootdir_first_cluster = 2;
|
||||
|
||||
// Sector 0: Boot sector
|
||||
// NOTE: We don't need an MBR, it is a waste of a good sector!
|
||||
fs->lba_begin = 0;
|
||||
if (!fatfs_create_boot_sector(ctx, fs, fs->lba_begin, volume_sectors, name, 1))
|
||||
return 0;
|
||||
|
||||
// First FAT LBA address
|
||||
fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
|
||||
|
||||
// The address of the first data cluster on this volume
|
||||
fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
|
||||
|
||||
// Initialise FSInfo sector
|
||||
if (!fatfs_create_fsinfo_sector(ctx, fs, fs->fs_info_sector))
|
||||
return 0;
|
||||
|
||||
// Initialise FAT sectors
|
||||
if (!fatfs_erase_fat(ctx, fs, 1))
|
||||
return 0;
|
||||
|
||||
// Erase Root directory
|
||||
if (!fatfs_erase_sectors(ctx, fs, fatfs_lba_of_cluster(fs, fs->rootdir_first_cluster), fs->sectors_per_cluster))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_format(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name)
|
||||
{
|
||||
// 2GB - 32K limit for safe behaviour for FAT16
|
||||
if (volume_sectors <= 4194304)
|
||||
return fatfs_format_fat16(ctx, fs, volume_sectors, name);
|
||||
else
|
||||
return fatfs_format_fat32(ctx, fs, volume_sectors, name);
|
||||
}
|
||||
#endif /*FATFS_INC_FORMAT_SUPPORT*/
|
||||
17
kernel/fs/fatfs/fat_format.h
Normal file
17
kernel/fs/fatfs/fat_format.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __FAT_FORMAT_H__
|
||||
#define __FAT_FORMAT_H__
|
||||
|
||||
#include "fat_defs.h"
|
||||
#include "fat_opts.h"
|
||||
#include "fat_access.h"
|
||||
|
||||
struct fat_ctx;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_format(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name);
|
||||
int fatfs_format_fat16(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name);
|
||||
int fatfs_format_fat32(struct fat_ctx *ctx, struct fatfs *fs, uint32 volume_sectors, const char *name);
|
||||
|
||||
#endif
|
||||
161
kernel/fs/fatfs/fat_list.h
Normal file
161
kernel/fs/fatfs/fat_list.h
Normal file
@ -0,0 +1,161 @@
|
||||
#ifndef __FAT_LIST_H__
|
||||
#define __FAT_LIST_H__
|
||||
|
||||
#ifndef FAT_ASSERT
|
||||
#define FAT_ASSERT(x)
|
||||
#endif
|
||||
|
||||
#ifndef FAT_INLINE
|
||||
#define FAT_INLINE
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Types
|
||||
//-----------------------------------------------------------------
|
||||
struct fat_list;
|
||||
|
||||
struct fat_node
|
||||
{
|
||||
struct fat_node *previous;
|
||||
struct fat_node *next;
|
||||
};
|
||||
|
||||
struct fat_list
|
||||
{
|
||||
struct fat_node *head;
|
||||
struct fat_node *tail;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Macros
|
||||
//-----------------------------------------------------------------
|
||||
#define fat_list_entry(p, t, m) p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0
|
||||
#define fat_list_next(l, p) (p)->next
|
||||
#define fat_list_prev(l, p) (p)->previous
|
||||
#define fat_list_first(l) (l)->head
|
||||
#define fat_list_last(l) (l)->tail
|
||||
#define fat_list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next)
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Inline Functions
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_init:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE void fat_list_init(struct fat_list *list)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
|
||||
list->head = list->tail = 0;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_remove:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE void fat_list_remove(struct fat_list *list, struct fat_node *node)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
FAT_ASSERT(node);
|
||||
|
||||
if(!node->previous)
|
||||
list->head = node->next;
|
||||
else
|
||||
node->previous->next = node->next;
|
||||
|
||||
if(!node->next)
|
||||
list->tail = node->previous;
|
||||
else
|
||||
node->next->previous = node->previous;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_insert_after:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE void fat_list_insert_after(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
FAT_ASSERT(node);
|
||||
FAT_ASSERT(new_node);
|
||||
|
||||
new_node->previous = node;
|
||||
new_node->next = node->next;
|
||||
if (!node->next)
|
||||
list->tail = new_node;
|
||||
else
|
||||
node->next->previous = new_node;
|
||||
node->next = new_node;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_insert_before:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE void fat_list_insert_before(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
FAT_ASSERT(node);
|
||||
FAT_ASSERT(new_node);
|
||||
|
||||
new_node->previous = node->previous;
|
||||
new_node->next = node;
|
||||
if (!node->previous)
|
||||
list->head = new_node;
|
||||
else
|
||||
node->previous->next = new_node;
|
||||
node->previous = new_node;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_insert_first:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE void fat_list_insert_first(struct fat_list *list, struct fat_node *node)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
FAT_ASSERT(node);
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
node->previous = 0;
|
||||
node->next = 0;
|
||||
}
|
||||
else
|
||||
fat_list_insert_before(list, list->head, node);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_insert_last:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE void fat_list_insert_last(struct fat_list *list, struct fat_node *node)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
FAT_ASSERT(node);
|
||||
|
||||
if (!list->tail)
|
||||
fat_list_insert_first(list, node);
|
||||
else
|
||||
fat_list_insert_after(list, list->tail, node);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_is_empty:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE int fat_list_is_empty(struct fat_list *list)
|
||||
{
|
||||
FAT_ASSERT(list);
|
||||
|
||||
return !list->head;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
// fat_list_pop_head:
|
||||
//-----------------------------------------------------------------
|
||||
static FAT_INLINE struct fat_node * fat_list_pop_head(struct fat_list *list)
|
||||
{
|
||||
struct fat_node * node;
|
||||
|
||||
FAT_ASSERT(list);
|
||||
|
||||
node = fat_list_first(list);
|
||||
if (node)
|
||||
fat_list_remove(list, node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
505
kernel/fs/fatfs/fat_misc.c
Normal file
505
kernel/fs/fatfs/fat_misc.c
Normal file
@ -0,0 +1,505 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "fat_misc.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lfn_cache_init: Clear long file name cache
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
lfn->no_of_strings = 0;
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
|
||||
// Zero out buffer also
|
||||
if (wipeTable)
|
||||
for (i=0;i<MAX_LONGFILENAME_ENTRIES;i++)
|
||||
memset(lfn->String[i], 0x00, MAX_LFN_ENTRY_LENGTH);
|
||||
#endif
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lfn_cache_entry - Function extracts long file name text from sector
|
||||
// at a specific offset
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer)
|
||||
{
|
||||
uint8 LFNIndex, i;
|
||||
LFNIndex = entryBuffer[0] & 0x1F;
|
||||
|
||||
// Limit file name to cache size!
|
||||
if (LFNIndex > MAX_LONGFILENAME_ENTRIES)
|
||||
return ;
|
||||
|
||||
// This is an error condition
|
||||
if (LFNIndex == 0)
|
||||
return ;
|
||||
|
||||
if (lfn->no_of_strings == 0)
|
||||
lfn->no_of_strings = LFNIndex;
|
||||
|
||||
lfn->String[LFNIndex-1][0] = entryBuffer[1];
|
||||
lfn->String[LFNIndex-1][1] = entryBuffer[3];
|
||||
lfn->String[LFNIndex-1][2] = entryBuffer[5];
|
||||
lfn->String[LFNIndex-1][3] = entryBuffer[7];
|
||||
lfn->String[LFNIndex-1][4] = entryBuffer[9];
|
||||
lfn->String[LFNIndex-1][5] = entryBuffer[0x0E];
|
||||
lfn->String[LFNIndex-1][6] = entryBuffer[0x10];
|
||||
lfn->String[LFNIndex-1][7] = entryBuffer[0x12];
|
||||
lfn->String[LFNIndex-1][8] = entryBuffer[0x14];
|
||||
lfn->String[LFNIndex-1][9] = entryBuffer[0x16];
|
||||
lfn->String[LFNIndex-1][10] = entryBuffer[0x18];
|
||||
lfn->String[LFNIndex-1][11] = entryBuffer[0x1C];
|
||||
lfn->String[LFNIndex-1][12] = entryBuffer[0x1E];
|
||||
|
||||
for (i=0; i<MAX_LFN_ENTRY_LENGTH; i++)
|
||||
if (lfn->String[LFNIndex-1][i]==0xFF)
|
||||
lfn->String[LFNIndex-1][i] = 0x20; // Replace with spaces
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lfn_cache_get: Get a reference to the long filename
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
char* fatfs_lfn_cache_get(struct lfn_cache *lfn)
|
||||
{
|
||||
// Null terminate long filename
|
||||
if (lfn->no_of_strings == MAX_LONGFILENAME_ENTRIES)
|
||||
lfn->Null = '\0';
|
||||
else if (lfn->no_of_strings)
|
||||
lfn->String[lfn->no_of_strings][0] = '\0';
|
||||
else
|
||||
lfn->String[0][0] = '\0';
|
||||
|
||||
return (char*)&lfn->String[0][0];
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_entry_lfn_text: If LFN text entry found
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
int fatfs_entry_lfn_text(struct fat_dir_entry *entry)
|
||||
{
|
||||
if ((entry->Attr & FILE_ATTR_LFN_TEXT) == FILE_ATTR_LFN_TEXT)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_entry_lfn_invalid: If SFN found not relating to LFN
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry)
|
||||
{
|
||||
if ( (entry->Name[0]==FILE_HEADER_BLANK) ||
|
||||
(entry->Name[0]==FILE_HEADER_DELETED)||
|
||||
(entry->Attr==FILE_ATTR_VOLUME_ID) ||
|
||||
(entry->Attr & FILE_ATTR_SYSHID) )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_entry_lfn_exists: If LFN exists and correlation SFN found
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry)
|
||||
{
|
||||
if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
|
||||
(entry->Name[0]!=FILE_HEADER_BLANK) &&
|
||||
(entry->Name[0]!=FILE_HEADER_DELETED) &&
|
||||
(entry->Attr!=FILE_ATTR_VOLUME_ID) &&
|
||||
(!(entry->Attr&FILE_ATTR_SYSHID)) &&
|
||||
(lfn->no_of_strings) )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_entry_sfn_only: If SFN only exists
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_entry_sfn_only(struct fat_dir_entry *entry)
|
||||
{
|
||||
if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
|
||||
(entry->Name[0]!=FILE_HEADER_BLANK) &&
|
||||
(entry->Name[0]!=FILE_HEADER_DELETED) &&
|
||||
(entry->Attr!=FILE_ATTR_VOLUME_ID) &&
|
||||
(!(entry->Attr&FILE_ATTR_SYSHID)) )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
// TODO: FILE_ATTR_SYSHID ?!?!??!
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_entry_is_dir: Returns 1 if a directory
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_entry_is_dir(struct fat_dir_entry *entry)
|
||||
{
|
||||
if (entry->Attr & FILE_TYPE_DIR)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_entry_is_file: Returns 1 is a file entry
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_entry_is_file(struct fat_dir_entry *entry)
|
||||
{
|
||||
if (entry->Attr & FILE_TYPE_FILE)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lfn_entries_required: Calculate number of 13 characters entries
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
int fatfs_lfn_entries_required(char *filename)
|
||||
{
|
||||
int length = (int)strlen(filename);
|
||||
|
||||
if (length)
|
||||
return (length + MAX_LFN_ENTRY_LENGTH - 1) / MAX_LFN_ENTRY_LENGTH;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_filename_to_lfn:
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk)
|
||||
{
|
||||
int i;
|
||||
int nameIndexes[MAX_LFN_ENTRY_LENGTH] = {1,3,5,7,9,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E};
|
||||
|
||||
// 13 characters entries
|
||||
int length = (int)strlen(filename);
|
||||
int entriesRequired = fatfs_lfn_entries_required(filename);
|
||||
|
||||
// Filename offset
|
||||
int start = entry * MAX_LFN_ENTRY_LENGTH;
|
||||
|
||||
// Initialise to zeros
|
||||
memset(buffer, 0x00, FAT_DIR_ENTRY_SIZE);
|
||||
|
||||
// LFN entry number
|
||||
buffer[0] = (uint8)(((entriesRequired-1)==entry)?(0x40|(entry+1)):(entry+1));
|
||||
|
||||
// LFN flag
|
||||
buffer[11] = 0x0F;
|
||||
|
||||
// Checksum of short filename
|
||||
buffer[13] = sfnChk;
|
||||
|
||||
// Copy to buffer
|
||||
for (i=0;i<MAX_LFN_ENTRY_LENGTH;i++)
|
||||
{
|
||||
if ( (start+i) < length )
|
||||
buffer[nameIndexes[i]] = filename[start+i];
|
||||
else if ( (start+i) == length )
|
||||
buffer[nameIndexes[i]] = 0x00;
|
||||
else
|
||||
{
|
||||
buffer[nameIndexes[i]] = 0xFF;
|
||||
buffer[nameIndexes[i]+1] = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_sfn_create_entry: Create the short filename directory entry
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Copy short filename
|
||||
for (i=0;i<FAT_SFN_SIZE_FULL;i++)
|
||||
entry->Name[i] = shortfilename[i];
|
||||
|
||||
// Unless we have a RTC we might as well set these to 1980
|
||||
entry->CrtTimeTenth = 0x00;
|
||||
entry->CrtTime[1] = entry->CrtTime[0] = 0x00;
|
||||
entry->CrtDate[1] = 0x00;
|
||||
entry->CrtDate[0] = 0x20;
|
||||
entry->LstAccDate[1] = 0x00;
|
||||
entry->LstAccDate[0] = 0x20;
|
||||
entry->WrtTime[1] = entry->WrtTime[0] = 0x00;
|
||||
entry->WrtDate[1] = 0x00;
|
||||
entry->WrtDate[0] = 0x20;
|
||||
|
||||
if (!dir)
|
||||
entry->Attr = FILE_TYPE_FILE;
|
||||
else
|
||||
entry->Attr = FILE_TYPE_DIR;
|
||||
|
||||
entry->NTRes = 0x00;
|
||||
|
||||
entry->FstClusHI = FAT_HTONS((uint16)((startCluster>>16) & 0xFFFF));
|
||||
entry->FstClusLO = FAT_HTONS((uint16)((startCluster>>0) & 0xFFFF));
|
||||
entry->FileSize = FAT_HTONL(size);
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lfn_create_sfn: Create a padded SFN
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_lfn_create_sfn(char *sfn_output, char *filename)
|
||||
{
|
||||
int i;
|
||||
int dotPos = -1;
|
||||
char ext[3];
|
||||
int pos;
|
||||
int len = (int)strlen(filename);
|
||||
|
||||
// Invalid to start with .
|
||||
if (filename[0]=='.')
|
||||
return 0;
|
||||
|
||||
memset(sfn_output, ' ', FAT_SFN_SIZE_FULL);
|
||||
memset(ext, ' ', 3);
|
||||
|
||||
// Find dot seperator
|
||||
for (i = 0; i< len; i++)
|
||||
{
|
||||
if (filename[i]=='.')
|
||||
dotPos = i;
|
||||
}
|
||||
|
||||
// Extract extensions
|
||||
if (dotPos!=-1)
|
||||
{
|
||||
// Copy first three chars of extension
|
||||
for (i = (dotPos+1); i < (dotPos+1+3); i++)
|
||||
if (i<len)
|
||||
ext[i-(dotPos+1)] = filename[i];
|
||||
|
||||
// Shorten the length to the dot position
|
||||
len = dotPos;
|
||||
}
|
||||
|
||||
// Add filename part
|
||||
pos = 0;
|
||||
for (i=0;i<len;i++)
|
||||
{
|
||||
if ( (filename[i]!=' ') && (filename[i]!='.') )
|
||||
{
|
||||
if (filename[i] >= 'a' && filename[i] <= 'z')
|
||||
sfn_output[pos++] = filename[i] - 'a' + 'A';
|
||||
else
|
||||
sfn_output[pos++] = filename[i];
|
||||
}
|
||||
|
||||
// Fill upto 8 characters
|
||||
if (pos==FAT_SFN_SIZE_PARTIAL)
|
||||
break;
|
||||
}
|
||||
|
||||
// Add extension part
|
||||
for (i=FAT_SFN_SIZE_PARTIAL;i<FAT_SFN_SIZE_FULL;i++)
|
||||
{
|
||||
if (ext[i-FAT_SFN_SIZE_PARTIAL] >= 'a' && ext[i-FAT_SFN_SIZE_PARTIAL] <= 'z')
|
||||
sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL] - 'a' + 'A';
|
||||
else
|
||||
sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_itoa:
|
||||
//-----------------------------------------------------------------------------
|
||||
static void fatfs_itoa(uint32 num, char *s)
|
||||
{
|
||||
char* cp;
|
||||
char outbuf[12];
|
||||
const char digits[] = "0123456789ABCDEF";
|
||||
|
||||
// Build string backwards
|
||||
cp = outbuf;
|
||||
do
|
||||
{
|
||||
*cp++ = digits[(int)(num % 10)];
|
||||
}
|
||||
while ((num /= 10) > 0);
|
||||
|
||||
*cp-- = 0;
|
||||
|
||||
// Copy in forwards
|
||||
while (cp >= outbuf)
|
||||
*s++ = *cp--;
|
||||
|
||||
*s = 0;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_lfn_generate_tail:
|
||||
// sfn_input = Input short filename, spaced format & in upper case
|
||||
// sfn_output = Output short filename with tail
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum)
|
||||
{
|
||||
int tail_chars;
|
||||
char tail_str[12];
|
||||
|
||||
if (tailNum > 99999)
|
||||
return 0;
|
||||
|
||||
// Convert to number
|
||||
memset(tail_str, 0x00, sizeof(tail_str));
|
||||
tail_str[0] = '~';
|
||||
fatfs_itoa(tailNum, tail_str+1);
|
||||
|
||||
// Copy in base filename
|
||||
memcpy(sfn_output, sfn_input, FAT_SFN_SIZE_FULL);
|
||||
|
||||
// Overwrite with tail
|
||||
tail_chars = (int)strlen(tail_str);
|
||||
memcpy(sfn_output+(FAT_SFN_SIZE_PARTIAL-tail_chars), tail_str, tail_chars);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_convert_from_fat_time: Convert FAT time to h/m/s
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds)
|
||||
{
|
||||
*hours = (fat_time >> FAT_TIME_HOURS_SHIFT) & FAT_TIME_HOURS_MASK;
|
||||
*minutes = (fat_time >> FAT_TIME_MINUTES_SHIFT) & FAT_TIME_MINUTES_MASK;
|
||||
*seconds = (fat_time >> FAT_TIME_SECONDS_SHIFT) & FAT_TIME_SECONDS_MASK;
|
||||
*seconds = *seconds * FAT_TIME_SECONDS_SCALE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_convert_from_fat_date: Convert FAT date to d/m/y
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year)
|
||||
{
|
||||
*day = (fat_date >> FAT_DATE_DAY_SHIFT) & FAT_DATE_DAY_MASK;
|
||||
*month = (fat_date >> FAT_DATE_MONTH_SHIFT) & FAT_DATE_MONTH_MASK;
|
||||
*year = (fat_date >> FAT_DATE_YEAR_SHIFT) & FAT_DATE_YEAR_MASK;
|
||||
*year = *year + FAT_DATE_YEAR_OFFSET;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_convert_to_fat_time: Convert h/m/s to FAT time
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds)
|
||||
{
|
||||
uint16 fat_time = 0;
|
||||
|
||||
// Most FAT times are to a resolution of 2 seconds
|
||||
seconds /= FAT_TIME_SECONDS_SCALE;
|
||||
|
||||
fat_time = (hours & FAT_TIME_HOURS_MASK) << FAT_TIME_HOURS_SHIFT;
|
||||
fat_time|= (minutes & FAT_TIME_MINUTES_MASK) << FAT_TIME_MINUTES_SHIFT;
|
||||
fat_time|= (seconds & FAT_TIME_SECONDS_MASK) << FAT_TIME_SECONDS_SHIFT;
|
||||
|
||||
return fat_time;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_convert_to_fat_date: Convert d/m/y to FAT date
|
||||
//-----------------------------------------------------------------------------
|
||||
uint16 fatfs_convert_to_fat_date(int day, int month, int year)
|
||||
{
|
||||
uint16 fat_date = 0;
|
||||
|
||||
// FAT dates are relative to 1980
|
||||
if (year >= FAT_DATE_YEAR_OFFSET)
|
||||
year -= FAT_DATE_YEAR_OFFSET;
|
||||
|
||||
fat_date = (day & FAT_DATE_DAY_MASK) << FAT_DATE_DAY_SHIFT;
|
||||
fat_date|= (month & FAT_DATE_MONTH_MASK) << FAT_DATE_MONTH_SHIFT;
|
||||
fat_date|= (year & FAT_DATE_YEAR_MASK) << FAT_DATE_YEAR_SHIFT;
|
||||
|
||||
return fat_date;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_print_sector:
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef FATFS_DEBUG
|
||||
void fatfs_print_sector(uint32 sector, uint8 *data)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
FAT_PRINTF(("Sector %d:\n", sector));
|
||||
|
||||
for (i=0;i<FAT_SECTOR_SIZE;i++)
|
||||
{
|
||||
if (!((i) % 16))
|
||||
{
|
||||
FAT_PRINTF((" %04d: ", i));
|
||||
}
|
||||
|
||||
FAT_PRINTF(("%02x", data[i]));
|
||||
if (!((i+1) % 4))
|
||||
{
|
||||
FAT_PRINTF((" "));
|
||||
}
|
||||
|
||||
if (!((i+1) % 16))
|
||||
{
|
||||
FAT_PRINTF((" "));
|
||||
for (j=0;j<16;j++)
|
||||
{
|
||||
char ch = data[i-15+j];
|
||||
|
||||
// Is printable?
|
||||
if (ch > 31 && ch < 127)
|
||||
{
|
||||
FAT_PRINTF(("%c", ch));
|
||||
}
|
||||
else
|
||||
{
|
||||
FAT_PRINTF(("."));
|
||||
}
|
||||
}
|
||||
|
||||
FAT_PRINTF(("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
63
kernel/fs/fatfs/fat_misc.h
Normal file
63
kernel/fs/fatfs/fat_misc.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef __FAT_MISC_H__
|
||||
#define __FAT_MISC_H__
|
||||
|
||||
#include "fat_defs.h"
|
||||
#include "fat_opts.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//-----------------------------------------------------------------------------
|
||||
#define MAX_LONGFILENAME_ENTRIES 20
|
||||
#define MAX_LFN_ENTRY_LENGTH 13
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Macros
|
||||
//-----------------------------------------------------------------------------
|
||||
#define GET_32BIT_WORD(buffer, location) ( ((uint32)buffer[location+3]<<24) + ((uint32)buffer[location+2]<<16) + ((uint32)buffer[location+1]<<8) + (uint32)buffer[location+0] )
|
||||
#define GET_16BIT_WORD(buffer, location) ( ((uint16)buffer[location+1]<<8) + (uint16)buffer[location+0] )
|
||||
|
||||
#define SET_32BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
|
||||
buffer[location+1] = (uint8)((value>>8)&0xFF); \
|
||||
buffer[location+2] = (uint8)((value>>16)&0xFF); \
|
||||
buffer[location+3] = (uint8)((value>>24)&0xFF); }
|
||||
|
||||
#define SET_16BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
|
||||
buffer[location+1] = (uint8)((value>>8)&0xFF); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Structures
|
||||
//-----------------------------------------------------------------------------
|
||||
struct lfn_cache
|
||||
{
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// Long File Name Structure (max 260 LFN length)
|
||||
uint8 String[MAX_LONGFILENAME_ENTRIES][MAX_LFN_ENTRY_LENGTH];
|
||||
uint8 Null;
|
||||
#endif
|
||||
uint8 no_of_strings;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable);
|
||||
void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer);
|
||||
char* fatfs_lfn_cache_get(struct lfn_cache *lfn);
|
||||
int fatfs_entry_lfn_text(struct fat_dir_entry *entry);
|
||||
int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry);
|
||||
int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry);
|
||||
int fatfs_entry_sfn_only(struct fat_dir_entry *entry);
|
||||
int fatfs_entry_is_dir(struct fat_dir_entry *entry);
|
||||
int fatfs_entry_is_file(struct fat_dir_entry *entry);
|
||||
int fatfs_lfn_entries_required(char *filename);
|
||||
void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk);
|
||||
void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir);
|
||||
int fatfs_lfn_create_sfn(char *sfn_output, char *filename);
|
||||
int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum);
|
||||
void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds);
|
||||
void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year);
|
||||
uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds);
|
||||
uint16 fatfs_convert_to_fat_date(int day, int month, int year);
|
||||
void fatfs_print_sector(uint32 sector, uint8 *data);
|
||||
|
||||
#endif
|
||||
90
kernel/fs/fatfs/fat_opts.h
Normal file
90
kernel/fs/fatfs/fat_opts.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef __FAT_OPTS_H__
|
||||
#define __FAT_OPTS_H__
|
||||
|
||||
#ifdef FATFS_USE_CUSTOM_OPTS_FILE
|
||||
#include "fat_custom.h"
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Configuration
|
||||
//-------------------------------------------------------------
|
||||
|
||||
// Is the processor little endian (1) or big endian (0)
|
||||
#ifndef FATFS_IS_LITTLE_ENDIAN
|
||||
#define FATFS_IS_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
// Max filename Length
|
||||
#ifndef FATFS_MAX_LONG_FILENAME
|
||||
#define FATFS_MAX_LONG_FILENAME 260
|
||||
#endif
|
||||
|
||||
// Max open files (reduce to lower memory requirements)
|
||||
#ifndef FATFS_MAX_OPEN_FILES
|
||||
#define FATFS_MAX_OPEN_FILES 2
|
||||
#endif
|
||||
|
||||
// Number of sectors per FAT_BUFFER (min 1)
|
||||
#ifndef FAT_BUFFER_SECTORS
|
||||
#define FAT_BUFFER_SECTORS 1
|
||||
#endif
|
||||
|
||||
// Max FAT sectors to buffer (min 1)
|
||||
// (mem used is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE)
|
||||
#ifndef FAT_BUFFERS
|
||||
#define FAT_BUFFERS 1
|
||||
#endif
|
||||
|
||||
// Size of cluster chain cache (can be undefined)
|
||||
// Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
|
||||
// Improves access speed considerably
|
||||
//#define FAT_CLUSTER_CACHE_ENTRIES 128
|
||||
|
||||
// Include support for writing files (1 / 0)?
|
||||
#ifndef FATFS_INC_WRITE_SUPPORT
|
||||
#define FATFS_INC_WRITE_SUPPORT 1
|
||||
#endif
|
||||
|
||||
// Support long filenames (1 / 0)?
|
||||
// (if not (0) only 8.3 format is supported)
|
||||
#ifndef FATFS_INC_LFN_SUPPORT
|
||||
#define FATFS_INC_LFN_SUPPORT 1
|
||||
#endif
|
||||
|
||||
// Support directory listing (1 / 0)?
|
||||
#ifndef FATFS_DIR_LIST_SUPPORT
|
||||
#define FATFS_DIR_LIST_SUPPORT 1
|
||||
#endif
|
||||
|
||||
// Support time/date (1 / 0)?
|
||||
#ifndef FATFS_INC_TIME_DATE_SUPPORT
|
||||
#define FATFS_INC_TIME_DATE_SUPPORT 0
|
||||
#endif
|
||||
|
||||
// Include support for formatting disks (1 / 0)?
|
||||
#ifndef FATFS_INC_FORMAT_SUPPORT
|
||||
#define FATFS_INC_FORMAT_SUPPORT 1
|
||||
#endif
|
||||
|
||||
// Sector size used
|
||||
#define FAT_SECTOR_SIZE 512
|
||||
|
||||
// Printf output (directory listing / debug)
|
||||
#ifndef FAT_PRINTF
|
||||
// Don't include stdio, but there is a printf function available
|
||||
#ifdef FAT_PRINTF_NOINC_STDIO
|
||||
extern int printf(const char* ctrl1, ... );
|
||||
#define FAT_PRINTF(a) printf a
|
||||
// Include stdio to use printf
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define FAT_PRINTF(a) printf a
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Time/Date support requires time.h
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
514
kernel/fs/fatfs/fat_string.c
Normal file
514
kernel/fs/fatfs/fat_string.c
Normal file
@ -0,0 +1,514 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "fat_string.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_total_path_levels: Take a filename and path and count the sub levels
|
||||
// of folders. E.g. C:\folder\file.zip = 1 level
|
||||
// Acceptable input formats are:
|
||||
// c:\folder\file.zip
|
||||
// /dev/etc/samba.conf
|
||||
// Returns: -1 = Error, 0 or more = Ok
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_total_path_levels(char *path)
|
||||
{
|
||||
int levels = 0;
|
||||
char expectedchar;
|
||||
|
||||
if (!path)
|
||||
return -1;
|
||||
|
||||
// Acceptable formats:
|
||||
// c:\folder\file.zip
|
||||
// /dev/etc/samba.conf
|
||||
if (*path == '/')
|
||||
{
|
||||
expectedchar = '/';
|
||||
path++;
|
||||
}
|
||||
else if (path[1] == ':' || path[2] == '\\')
|
||||
{
|
||||
expectedchar = '\\';
|
||||
path += 3;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
// Count levels in path string
|
||||
while (*path)
|
||||
{
|
||||
// Fast forward through actual subdir text to next slash
|
||||
for (; *path; )
|
||||
{
|
||||
// If slash detected escape from for loop
|
||||
if (*path == expectedchar) { path++; break; }
|
||||
path++;
|
||||
}
|
||||
|
||||
// Increase number of subdirs founds
|
||||
levels++;
|
||||
}
|
||||
|
||||
// Subtract the file itself
|
||||
return levels-1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_get_substring: Get a substring from 'path' which contains the folder
|
||||
// (or file) at the specified level.
|
||||
// E.g. C:\folder\file.zip : Level 0 = C:\folder, Level 1 = file.zip
|
||||
// Returns: -1 = Error, 0 = Ok
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_get_substring(char *path, int levelreq, char *output, int max_len)
|
||||
{
|
||||
int i;
|
||||
int pathlen=0;
|
||||
int levels=0;
|
||||
int copypnt=0;
|
||||
char expectedchar;
|
||||
|
||||
if (!path || max_len <= 0)
|
||||
return -1;
|
||||
|
||||
// Acceptable formats:
|
||||
// c:\folder\file.zip
|
||||
// /dev/etc/samba.conf
|
||||
if (*path == '/')
|
||||
{
|
||||
expectedchar = '/';
|
||||
path++;
|
||||
}
|
||||
else if (path[1] == ':' || path[2] == '\\')
|
||||
{
|
||||
expectedchar = '\\';
|
||||
path += 3;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
|
||||
// Get string length of path
|
||||
pathlen = (int)strlen (path);
|
||||
|
||||
// Loop through the number of times as characters in 'path'
|
||||
for (i = 0; i<pathlen; i++)
|
||||
{
|
||||
// If a '\' is found then increase level
|
||||
if (*path == expectedchar) levels++;
|
||||
|
||||
// If correct level and the character is not a '\' or '/' then copy text to 'output'
|
||||
if ( (levels == levelreq) && (*path != expectedchar) && (copypnt < (max_len-1)))
|
||||
output[copypnt++] = *path;
|
||||
|
||||
// Increment through path string
|
||||
path++;
|
||||
}
|
||||
|
||||
// Null Terminate
|
||||
output[copypnt] = '\0';
|
||||
|
||||
// If a string was copied return 0 else return 1
|
||||
if (output[0] != '\0')
|
||||
return 0; // OK
|
||||
else
|
||||
return -1; // Error
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_split_path: Full path contains the passed in string.
|
||||
// Returned is the path string and file Name string
|
||||
// E.g. C:\folder\file.zip -> path = C:\folder filename = file.zip
|
||||
// E.g. C:\file.zip -> path = [blank] filename = file.zip
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_split_path(char *full_path, char *path, int max_path, char *filename, int max_filename)
|
||||
{
|
||||
int strindex;
|
||||
|
||||
// Count the levels to the filepath
|
||||
int levels = fatfs_total_path_levels(full_path);
|
||||
if (levels == -1)
|
||||
return -1;
|
||||
|
||||
// Get filename part of string
|
||||
if (fatfs_get_substring(full_path, levels, filename, max_filename) != 0)
|
||||
return -1;
|
||||
|
||||
// If root file
|
||||
if (levels == 0)
|
||||
path[0] = '\0';
|
||||
else
|
||||
{
|
||||
strindex = (int)strlen(full_path) - (int)strlen(filename);
|
||||
if (strindex > max_path)
|
||||
strindex = max_path;
|
||||
|
||||
memcpy(path, full_path, strindex);
|
||||
path[strindex-1] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// FileString_StrCmpNoCase: Compare two strings case with case sensitivity
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FileString_StrCmpNoCase(char *s1, char *s2, int n)
|
||||
{
|
||||
int diff;
|
||||
char a,b;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
a = *s1;
|
||||
b = *s2;
|
||||
|
||||
// Make lower case if uppercase
|
||||
if ((a>='A') && (a<='Z'))
|
||||
a+= 32;
|
||||
if ((b>='A') && (b<='Z'))
|
||||
b+= 32;
|
||||
|
||||
diff = a - b;
|
||||
|
||||
// If different
|
||||
if (diff)
|
||||
return diff;
|
||||
|
||||
// If run out of strings
|
||||
if ( (*s1 == 0) || (*s2 == 0) )
|
||||
break;
|
||||
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// FileString_GetExtension: Get index to extension within filename
|
||||
// Returns -1 if not found or index otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FileString_GetExtension(char *str)
|
||||
{
|
||||
int dotPos = -1;
|
||||
char *strSrc = str;
|
||||
|
||||
// Find last '.' in string (if at all)
|
||||
while (*strSrc)
|
||||
{
|
||||
if (*strSrc=='.')
|
||||
dotPos = (int)(strSrc-str);
|
||||
|
||||
strSrc++;
|
||||
}
|
||||
|
||||
return dotPos;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// FileString_TrimLength: Get length of string excluding trailing spaces
|
||||
// Returns -1 if not found or index otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FileString_TrimLength(char *str, int strLen)
|
||||
{
|
||||
int length = strLen;
|
||||
char *strSrc = str+strLen-1;
|
||||
|
||||
// Find last non white space
|
||||
while (strLen != 0)
|
||||
{
|
||||
if (*strSrc == ' ')
|
||||
length = (int)(strSrc - str);
|
||||
else
|
||||
break;
|
||||
|
||||
strSrc--;
|
||||
strLen--;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_compare_names: Compare two filenames (without copying or changing origonals)
|
||||
// Returns 1 if match, 0 if not
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_compare_names(char* strA, char* strB)
|
||||
{
|
||||
char *ext1 = NULL;
|
||||
char *ext2 = NULL;
|
||||
int ext1Pos, ext2Pos;
|
||||
int file1Len, file2Len;
|
||||
|
||||
// Get both files extension
|
||||
ext1Pos = FileString_GetExtension(strA);
|
||||
ext2Pos = FileString_GetExtension(strB);
|
||||
|
||||
// NOTE: Extension position can be different for matching
|
||||
// filename if trailing space are present before it!
|
||||
// Check that if one has an extension, so does the other
|
||||
if ((ext1Pos==-1) && (ext2Pos!=-1))
|
||||
return 0;
|
||||
if ((ext2Pos==-1) && (ext1Pos!=-1))
|
||||
return 0;
|
||||
|
||||
// If they both have extensions, compare them
|
||||
if (ext1Pos!=-1)
|
||||
{
|
||||
// Set pointer to start of extension
|
||||
ext1 = strA+ext1Pos+1;
|
||||
ext2 = strB+ext2Pos+1;
|
||||
|
||||
// Verify that the file extension lengths match!
|
||||
if (strlen(ext1) != strlen(ext2))
|
||||
return 0;
|
||||
|
||||
// If they dont match
|
||||
if (FileString_StrCmpNoCase(ext1, ext2, (int)strlen(ext1))!=0)
|
||||
return 0;
|
||||
|
||||
// Filelength is upto extensions
|
||||
file1Len = ext1Pos;
|
||||
file2Len = ext2Pos;
|
||||
}
|
||||
// No extensions
|
||||
else
|
||||
{
|
||||
// Filelength is actual filelength
|
||||
file1Len = (int)strlen(strA);
|
||||
file2Len = (int)strlen(strB);
|
||||
}
|
||||
|
||||
// Find length without trailing spaces (before ext)
|
||||
file1Len = FileString_TrimLength(strA, file1Len);
|
||||
file2Len = FileString_TrimLength(strB, file2Len);
|
||||
|
||||
// Check the file lengths match
|
||||
if (file1Len!=file2Len)
|
||||
return 0;
|
||||
|
||||
// Compare main part of filenames
|
||||
if (FileString_StrCmpNoCase(strA, strB, file1Len)!=0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_string_ends_with_slash: Does the string end with a slash (\ or /)
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_string_ends_with_slash(char *path)
|
||||
{
|
||||
if (path)
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
// Last character?
|
||||
if (!(*(path+1)))
|
||||
{
|
||||
if (*path == '\\' || *path == '/')
|
||||
return 1;
|
||||
}
|
||||
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_get_sfn_display_name: Get display name for SFN entry
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_get_sfn_display_name(char* out, char* in)
|
||||
{
|
||||
int len = 0;
|
||||
while (*in && len <= 11)
|
||||
{
|
||||
char a = *in++;
|
||||
|
||||
if (a == ' ')
|
||||
continue;
|
||||
// Make lower case if uppercase
|
||||
else if ((a>='A') && (a<='Z'))
|
||||
a+= 32;
|
||||
|
||||
*out++ = a;
|
||||
len++;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_get_extension: Get extension of filename passed in 'filename'.
|
||||
// Returned extension is always lower case.
|
||||
// Returns: 1 if ok, 0 if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_get_extension(char* filename, char* out, int maxlen)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
// Get files extension offset
|
||||
int ext_pos = FileString_GetExtension(filename);
|
||||
|
||||
if (ext_pos > 0 && out && maxlen)
|
||||
{
|
||||
filename += ext_pos + 1;
|
||||
|
||||
while (*filename && len < (maxlen-1))
|
||||
{
|
||||
char a = *filename++;
|
||||
|
||||
// Make lowercase if uppercase
|
||||
if ((a>='A') && (a<='Z'))
|
||||
a+= 32;
|
||||
|
||||
*out++ = a;
|
||||
len++;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_create_path_string: Append path & filename to create file path string.
|
||||
// Returns: 1 if ok, 0 if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen)
|
||||
{
|
||||
int len = 0;
|
||||
char last = 0;
|
||||
char seperator = '/';
|
||||
|
||||
if (path && filename && out && maxlen > 0)
|
||||
{
|
||||
while (*path && len < (maxlen-2))
|
||||
{
|
||||
last = *path++;
|
||||
if (last == '\\')
|
||||
seperator = '\\';
|
||||
*out++ = last;
|
||||
len++;
|
||||
}
|
||||
|
||||
// Add a seperator if trailing one not found
|
||||
if (last != '\\' && last != '/')
|
||||
*out++ = seperator;
|
||||
|
||||
while (*filename && len < (maxlen-1))
|
||||
{
|
||||
*out++ = *filename++;
|
||||
len++;
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Test Bench
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef FAT_STRING_TESTBENCH
|
||||
void main(void)
|
||||
{
|
||||
char output[255];
|
||||
char output2[255];
|
||||
|
||||
assert(fatfs_total_path_levels("C:\\folder\\file.zip") == 1);
|
||||
assert(fatfs_total_path_levels("C:\\file.zip") == 0);
|
||||
assert(fatfs_total_path_levels("C:\\folder\\folder2\\file.zip") == 2);
|
||||
assert(fatfs_total_path_levels("C:\\") == -1);
|
||||
assert(fatfs_total_path_levels("") == -1);
|
||||
assert(fatfs_total_path_levels("/dev/etc/file.zip") == 2);
|
||||
assert(fatfs_total_path_levels("/dev/file.zip") == 1);
|
||||
|
||||
assert(fatfs_get_substring("C:\\folder\\file.zip", 0, output, sizeof(output)) == 0);
|
||||
assert(strcmp(output, "folder") == 0);
|
||||
|
||||
assert(fatfs_get_substring("C:\\folder\\file.zip", 1, output, sizeof(output)) == 0);
|
||||
assert(strcmp(output, "file.zip") == 0);
|
||||
|
||||
assert(fatfs_get_substring("/dev/etc/file.zip", 0, output, sizeof(output)) == 0);
|
||||
assert(strcmp(output, "dev") == 0);
|
||||
|
||||
assert(fatfs_get_substring("/dev/etc/file.zip", 1, output, sizeof(output)) == 0);
|
||||
assert(strcmp(output, "etc") == 0);
|
||||
|
||||
assert(fatfs_get_substring("/dev/etc/file.zip", 2, output, sizeof(output)) == 0);
|
||||
assert(strcmp(output, "file.zip") == 0);
|
||||
|
||||
assert(fatfs_split_path("C:\\folder\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
|
||||
assert(strcmp(output, "C:\\folder") == 0);
|
||||
assert(strcmp(output2, "file.zip") == 0);
|
||||
|
||||
assert(fatfs_split_path("C:\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
|
||||
assert(output[0] == 0);
|
||||
assert(strcmp(output2, "file.zip") == 0);
|
||||
|
||||
assert(fatfs_split_path("/dev/etc/file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
|
||||
assert(strcmp(output, "/dev/etc") == 0);
|
||||
assert(strcmp(output2, "file.zip") == 0);
|
||||
|
||||
assert(FileString_GetExtension("C:\\file.zip") == strlen("C:\\file"));
|
||||
assert(FileString_GetExtension("C:\\file.zip.ext") == strlen("C:\\file.zip"));
|
||||
assert(FileString_GetExtension("C:\\file.zip.") == strlen("C:\\file.zip"));
|
||||
|
||||
assert(FileString_TrimLength("C:\\file.zip", strlen("C:\\file.zip")) == strlen("C:\\file.zip"));
|
||||
assert(FileString_TrimLength("C:\\file.zip ", strlen("C:\\file.zip ")) == strlen("C:\\file.zip"));
|
||||
assert(FileString_TrimLength(" ", strlen(" ")) == 0);
|
||||
|
||||
assert(fatfs_compare_names("C:\\file.ext", "C:\\file.ext") == 1);
|
||||
assert(fatfs_compare_names("C:\\file2.ext", "C:\\file.ext") == 0);
|
||||
assert(fatfs_compare_names("C:\\file .ext", "C:\\file.ext") == 1);
|
||||
assert(fatfs_compare_names("C:\\file .ext", "C:\\file2.ext") == 0);
|
||||
|
||||
assert(fatfs_string_ends_with_slash("C:\\folder") == 0);
|
||||
assert(fatfs_string_ends_with_slash("C:\\folder\\") == 1);
|
||||
assert(fatfs_string_ends_with_slash("/path") == 0);
|
||||
assert(fatfs_string_ends_with_slash("/path/a") == 0);
|
||||
assert(fatfs_string_ends_with_slash("/path/") == 1);
|
||||
|
||||
assert(fatfs_get_extension("/mypath/file.wav", output, 4) == 1);
|
||||
assert(strcmp(output, "wav") == 0);
|
||||
assert(fatfs_get_extension("/mypath/file.WAV", output, 4) == 1);
|
||||
assert(strcmp(output, "wav") == 0);
|
||||
assert(fatfs_get_extension("/mypath/file.zip", output, 4) == 1);
|
||||
assert(strcmp(output, "ext") != 0);
|
||||
|
||||
assert(fatfs_create_path_string("/mydir1", "myfile.txt", output, sizeof(output)) == 1);
|
||||
assert(strcmp(output, "/mydir1/myfile.txt") == 0);
|
||||
assert(fatfs_create_path_string("/mydir2/", "myfile2.txt", output, sizeof(output)) == 1);
|
||||
assert(strcmp(output, "/mydir2/myfile2.txt") == 0);
|
||||
assert(fatfs_create_path_string("C:\\mydir3", "myfile3.txt", output, sizeof(output)) == 1);
|
||||
assert(strcmp(output, "C:\\mydir3\\myfile3.txt") == 0);
|
||||
}
|
||||
#endif
|
||||
20
kernel/fs/fatfs/fat_string.h
Normal file
20
kernel/fs/fatfs/fat_string.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef __FILESTRING_H__
|
||||
#define __FILESTRING_H__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_total_path_levels(char *path);
|
||||
int fatfs_get_substring(char *Path, int levelreq, char *output, int max_len);
|
||||
int fatfs_split_path(char *FullPath, char *Path, int max_path, char *FileName, int max_filename);
|
||||
int fatfs_compare_names(char* strA, char* strB);
|
||||
int fatfs_string_ends_with_slash(char *path);
|
||||
int fatfs_get_sfn_display_name(char* out, char* in);
|
||||
int fatfs_get_extension(char* filename, char* out, int maxlen);
|
||||
int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen);
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
478
kernel/fs/fatfs/fat_table.c
Normal file
478
kernel/fs/fatfs/fat_table.c
Normal file
@ -0,0 +1,478 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include "fat_defs.h"
|
||||
#include "fat_access.h"
|
||||
#include "fat_table.h"
|
||||
|
||||
#ifndef FAT_BUFFERS
|
||||
#define FAT_BUFFERS 1
|
||||
#endif
|
||||
|
||||
#ifndef FAT_BUFFER_SECTORS
|
||||
#define FAT_BUFFER_SECTORS 1
|
||||
#endif
|
||||
|
||||
#if FAT_BUFFERS < 1 || FAT_BUFFER_SECTORS < 1
|
||||
#error "FAT_BUFFERS & FAT_BUFFER_SECTORS must be at least 1"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT Sector Buffer
|
||||
//-----------------------------------------------------------------------------
|
||||
#define FAT32_GET_32BIT_WORD(pbuf, location) ( GET_32BIT_WORD(pbuf->ptr, location) )
|
||||
#define FAT32_SET_32BIT_WORD(pbuf, location, value) { SET_32BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
|
||||
#define FAT16_GET_16BIT_WORD(pbuf, location) ( GET_16BIT_WORD(pbuf->ptr, location) )
|
||||
#define FAT16_SET_16BIT_WORD(pbuf, location, value) { SET_16BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_fat_init:
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_fat_init(struct fatfs *fs)
|
||||
{
|
||||
int i;
|
||||
|
||||
// FAT buffer chain head
|
||||
fs->fat_buffer_head = NULL;
|
||||
|
||||
for (i=0;i<FAT_BUFFERS;i++)
|
||||
{
|
||||
// Initialise buffers to invalid
|
||||
fs->fat_buffers[i].address = FAT32_INVALID_CLUSTER;
|
||||
fs->fat_buffers[i].dirty = 0;
|
||||
memset(fs->fat_buffers[i].sector, 0x00, sizeof(fs->fat_buffers[i].sector));
|
||||
fs->fat_buffers[i].ptr = NULL;
|
||||
|
||||
// Add to head of queue
|
||||
fs->fat_buffers[i].next = fs->fat_buffer_head;
|
||||
fs->fat_buffer_head = &fs->fat_buffers[i];
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_fat_writeback: Writeback 'dirty' FAT sectors to disk
|
||||
//-----------------------------------------------------------------------------
|
||||
static int fatfs_fat_writeback(struct fat_ctx *ctx, struct fatfs *fs, struct fat_buffer *pcur)
|
||||
{
|
||||
if (pcur)
|
||||
{
|
||||
// Writeback sector if changed
|
||||
if (pcur->dirty)
|
||||
{
|
||||
if (fs->disk_io.write_media)
|
||||
{
|
||||
uint32 sectors = FAT_BUFFER_SECTORS;
|
||||
uint32 offset = pcur->address - fs->fat_begin_lba;
|
||||
|
||||
// Limit to sectors used for the FAT
|
||||
if ((offset + FAT_BUFFER_SECTORS) <= fs->fat_sectors)
|
||||
sectors = FAT_BUFFER_SECTORS;
|
||||
else
|
||||
sectors = fs->fat_sectors - offset;
|
||||
|
||||
if (!fs->disk_io.write_media(ctx, pcur->address, pcur->sector, sectors))
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcur->dirty = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_fat_read_sector: Read a FAT sector
|
||||
//-----------------------------------------------------------------------------
|
||||
static struct fat_buffer *fatfs_fat_read_sector(struct fat_ctx *ctx, struct fatfs *fs, uint32 sector)
|
||||
{
|
||||
struct fat_buffer *last = NULL;
|
||||
struct fat_buffer *pcur = fs->fat_buffer_head;
|
||||
|
||||
// Itterate through sector buffer list
|
||||
while (pcur)
|
||||
{
|
||||
// Sector within this buffer?
|
||||
if ((sector >= pcur->address) && (sector < (pcur->address + FAT_BUFFER_SECTORS)))
|
||||
break;
|
||||
|
||||
// End of list?
|
||||
if (pcur->next == NULL)
|
||||
{
|
||||
// Remove buffer from list
|
||||
if (last)
|
||||
last->next = NULL;
|
||||
// We the first and last buffer in the chain?
|
||||
else
|
||||
fs->fat_buffer_head = NULL;
|
||||
}
|
||||
|
||||
last = pcur;
|
||||
pcur = pcur->next;
|
||||
}
|
||||
|
||||
// We found the sector already in FAT buffer chain
|
||||
if (pcur)
|
||||
{
|
||||
pcur->ptr = (uint8 *)(pcur->sector + ((sector - pcur->address) * FAT_SECTOR_SIZE));
|
||||
return pcur;
|
||||
}
|
||||
|
||||
// Else, we removed the last item from the list
|
||||
pcur = last;
|
||||
|
||||
// Add to start of sector buffer list (now newest sector)
|
||||
pcur->next = fs->fat_buffer_head;
|
||||
fs->fat_buffer_head = pcur;
|
||||
|
||||
// Writeback sector if changed
|
||||
if (pcur->dirty)
|
||||
if (!fatfs_fat_writeback(ctx, fs, pcur))
|
||||
return 0;
|
||||
|
||||
// Address is now new sector
|
||||
pcur->address = sector;
|
||||
|
||||
// Read next sector
|
||||
if (!fs->disk_io.read_media(ctx, pcur->address, pcur->sector, FAT_BUFFER_SECTORS))
|
||||
{
|
||||
// Read failed, invalidate buffer address
|
||||
pcur->address = FAT32_INVALID_CLUSTER;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pcur->ptr = pcur->sector;
|
||||
return pcur;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_fat_purge: Purge 'dirty' FAT sectors to disk
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_fat_purge(struct fat_ctx *ctx, struct fatfs *fs)
|
||||
{
|
||||
struct fat_buffer *pcur = fs->fat_buffer_head;
|
||||
|
||||
// Itterate through sector buffer list
|
||||
while (pcur)
|
||||
{
|
||||
// Writeback sector if changed
|
||||
if (pcur->dirty)
|
||||
if (!fatfs_fat_writeback(ctx, fs, pcur))
|
||||
return 0;
|
||||
|
||||
pcur = pcur->next;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// General FAT Table Operations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_find_next_cluster: Return cluster number of next cluster in chain by
|
||||
// reading FAT table and traversing it. Return 0xffffffff for end of chain.
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 fatfs_find_next_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 current_cluster)
|
||||
{
|
||||
uint32 fat_sector_offset, position;
|
||||
uint32 nextcluster;
|
||||
struct fat_buffer *pbuf;
|
||||
|
||||
// Why is '..' labelled with cluster 0 when it should be 2 ??
|
||||
if (current_cluster == 0)
|
||||
current_cluster = 2;
|
||||
|
||||
// Find which sector of FAT table to read
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
fat_sector_offset = current_cluster / 256;
|
||||
else
|
||||
fat_sector_offset = current_cluster / 128;
|
||||
|
||||
// Read FAT sector into buffer
|
||||
pbuf = fatfs_fat_read_sector(ctx, fs, fs->fat_begin_lba+fat_sector_offset);
|
||||
if (!pbuf)
|
||||
return (FAT32_LAST_CLUSTER);
|
||||
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
{
|
||||
// Find 32 bit entry of current sector relating to cluster number
|
||||
position = (current_cluster - (fat_sector_offset * 256)) * 2;
|
||||
|
||||
// Read Next Clusters value from Sector Buffer
|
||||
nextcluster = FAT16_GET_16BIT_WORD(pbuf, (uint16)position);
|
||||
|
||||
// If end of chain found
|
||||
if (nextcluster >= 0xFFF8 && nextcluster <= 0xFFFF)
|
||||
return (FAT32_LAST_CLUSTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find 32 bit entry of current sector relating to cluster number
|
||||
position = (current_cluster - (fat_sector_offset * 128)) * 4;
|
||||
|
||||
// Read Next Clusters value from Sector Buffer
|
||||
nextcluster = FAT32_GET_32BIT_WORD(pbuf, (uint16)position);
|
||||
|
||||
// Mask out MS 4 bits (its 28bit addressing)
|
||||
nextcluster = nextcluster & 0x0FFFFFFF;
|
||||
|
||||
// If end of chain found
|
||||
if (nextcluster >= 0x0FFFFFF8 && nextcluster <= 0x0FFFFFFF)
|
||||
return (FAT32_LAST_CLUSTER);
|
||||
}
|
||||
|
||||
// Else return next cluster
|
||||
return (nextcluster);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_set_fs_info_next_free_cluster: Write the next free cluster to the FSINFO table
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_set_fs_info_next_free_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 newValue)
|
||||
{
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
;
|
||||
else
|
||||
{
|
||||
// Load sector to change it
|
||||
struct fat_buffer *pbuf = fatfs_fat_read_sector(ctx, fs, fs->lba_begin+fs->fs_info_sector);
|
||||
if (!pbuf)
|
||||
return ;
|
||||
|
||||
// Change
|
||||
FAT32_SET_32BIT_WORD(pbuf, 492, newValue);
|
||||
fs->next_free_cluster = newValue;
|
||||
|
||||
// Write back FSINFO sector to disk
|
||||
if (fs->disk_io.write_media)
|
||||
fs->disk_io.write_media(ctx, pbuf->address, pbuf->sector, 1);
|
||||
|
||||
// Invalidate cache entry
|
||||
pbuf->address = FAT32_INVALID_CLUSTER;
|
||||
pbuf->dirty = 0;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_find_blank_cluster: Find a free cluster entry by reading the FAT
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_find_blank_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster)
|
||||
{
|
||||
uint32 fat_sector_offset, position;
|
||||
uint32 nextcluster;
|
||||
uint32 current_cluster = start_cluster;
|
||||
struct fat_buffer *pbuf;
|
||||
|
||||
do
|
||||
{
|
||||
// Find which sector of FAT table to read
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
fat_sector_offset = current_cluster / 256;
|
||||
else
|
||||
fat_sector_offset = current_cluster / 128;
|
||||
|
||||
if ( fat_sector_offset < fs->fat_sectors)
|
||||
{
|
||||
// Read FAT sector into buffer
|
||||
pbuf = fatfs_fat_read_sector(ctx, fs, fs->fat_begin_lba+fat_sector_offset);
|
||||
if (!pbuf)
|
||||
return 0;
|
||||
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
{
|
||||
// Find 32 bit entry of current sector relating to cluster number
|
||||
position = (current_cluster - (fat_sector_offset * 256)) * 2;
|
||||
|
||||
// Read Next Clusters value from Sector Buffer
|
||||
nextcluster = FAT16_GET_16BIT_WORD(pbuf, (uint16)position);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find 32 bit entry of current sector relating to cluster number
|
||||
position = (current_cluster - (fat_sector_offset * 128)) * 4;
|
||||
|
||||
// Read Next Clusters value from Sector Buffer
|
||||
nextcluster = FAT32_GET_32BIT_WORD(pbuf, (uint16)position);
|
||||
|
||||
// Mask out MS 4 bits (its 28bit addressing)
|
||||
nextcluster = nextcluster & 0x0FFFFFFF;
|
||||
}
|
||||
|
||||
if (nextcluster !=0 )
|
||||
current_cluster++;
|
||||
}
|
||||
else
|
||||
// Otherwise, run out of FAT sectors to check...
|
||||
return 0;
|
||||
}
|
||||
while (nextcluster != 0x0);
|
||||
|
||||
// Found blank entry
|
||||
*free_cluster = current_cluster;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_fat_set_cluster: Set a cluster link in the chain. NOTE: Immediate
|
||||
// write (slow).
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_fat_set_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 next_cluster)
|
||||
{
|
||||
struct fat_buffer *pbuf;
|
||||
uint32 fat_sector_offset, position;
|
||||
|
||||
// Find which sector of FAT table to read
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
fat_sector_offset = cluster / 256;
|
||||
else
|
||||
fat_sector_offset = cluster / 128;
|
||||
|
||||
// Read FAT sector into buffer
|
||||
pbuf = fatfs_fat_read_sector(ctx, fs, fs->fat_begin_lba+fat_sector_offset);
|
||||
if (!pbuf)
|
||||
return 0;
|
||||
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
{
|
||||
// Find 16 bit entry of current sector relating to cluster number
|
||||
position = (cluster - (fat_sector_offset * 256)) * 2;
|
||||
|
||||
// Write Next Clusters value to Sector Buffer
|
||||
FAT16_SET_16BIT_WORD(pbuf, (uint16)position, ((uint16)next_cluster));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find 32 bit entry of current sector relating to cluster number
|
||||
position = (cluster - (fat_sector_offset * 128)) * 4;
|
||||
|
||||
// Write Next Clusters value to Sector Buffer
|
||||
FAT32_SET_32BIT_WORD(pbuf, (uint16)position, next_cluster);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_free_cluster_chain: Follow a chain marking each element as free
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_free_cluster_chain(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster)
|
||||
{
|
||||
uint32 last_cluster;
|
||||
uint32 next_cluster = start_cluster;
|
||||
|
||||
// Loop until end of chain
|
||||
while ( (next_cluster != FAT32_LAST_CLUSTER) && (next_cluster != 0x00000000) )
|
||||
{
|
||||
last_cluster = next_cluster;
|
||||
|
||||
// Find next link
|
||||
next_cluster = fatfs_find_next_cluster(ctx, fs, next_cluster);
|
||||
|
||||
// Clear last link
|
||||
fatfs_fat_set_cluster(ctx, fs, last_cluster, 0x00000000);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_fat_add_cluster_to_chain: Follow a chain marking and then add a new entry
|
||||
// to the current tail.
|
||||
//-----------------------------------------------------------------------------
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
int fatfs_fat_add_cluster_to_chain(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster, uint32 newEntry)
|
||||
{
|
||||
uint32 last_cluster = FAT32_LAST_CLUSTER;
|
||||
uint32 next_cluster = start_cluster;
|
||||
|
||||
if (start_cluster == FAT32_LAST_CLUSTER)
|
||||
return 0;
|
||||
|
||||
// Loop until end of chain
|
||||
while ( next_cluster != FAT32_LAST_CLUSTER )
|
||||
{
|
||||
last_cluster = next_cluster;
|
||||
|
||||
// Find next link
|
||||
next_cluster = fatfs_find_next_cluster(ctx, fs, next_cluster);
|
||||
if (!next_cluster)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add link in for new cluster
|
||||
fatfs_fat_set_cluster(ctx, fs, last_cluster, newEntry);
|
||||
|
||||
// Mark new cluster as end of chain
|
||||
fatfs_fat_set_cluster(ctx, fs, newEntry, FAT32_LAST_CLUSTER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_count_free_clusters:
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32 fatfs_count_free_clusters(struct fat_ctx *ctx, struct fatfs *fs)
|
||||
{
|
||||
uint32 i,j;
|
||||
uint32 count = 0;
|
||||
struct fat_buffer *pbuf;
|
||||
|
||||
for (i = 0; i < fs->fat_sectors; i++)
|
||||
{
|
||||
// Read FAT sector into buffer
|
||||
pbuf = fatfs_fat_read_sector(ctx, fs, fs->fat_begin_lba + i);
|
||||
if (!pbuf)
|
||||
break;
|
||||
|
||||
for (j = 0; j < FAT_SECTOR_SIZE; )
|
||||
{
|
||||
if (fs->fat_type == FAT_TYPE_16)
|
||||
{
|
||||
if (FAT16_GET_16BIT_WORD(pbuf, (uint16)j) == 0)
|
||||
count++;
|
||||
|
||||
j += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FAT32_GET_32BIT_WORD(pbuf, (uint16)j) == 0)
|
||||
count++;
|
||||
|
||||
j += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
22
kernel/fs/fatfs/fat_table.h
Normal file
22
kernel/fs/fatfs/fat_table.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __FAT_TABLE_H__
|
||||
#define __FAT_TABLE_H__
|
||||
|
||||
#include "fat_opts.h"
|
||||
#include "fat_misc.h"
|
||||
|
||||
struct fat_ctx;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
void fatfs_fat_init(struct fatfs *fs);
|
||||
int fatfs_fat_purge(struct fat_ctx *ctx, struct fatfs *fs);
|
||||
uint32 fatfs_find_next_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 current_cluster);
|
||||
void fatfs_set_fs_info_next_free_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 newValue);
|
||||
int fatfs_find_blank_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster);
|
||||
int fatfs_fat_set_cluster(struct fat_ctx *ctx, struct fatfs *fs, uint32 cluster, uint32 next_cluster);
|
||||
int fatfs_fat_add_cluster_to_chain(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster, uint32 newEntry);
|
||||
int fatfs_free_cluster_chain(struct fat_ctx *ctx, struct fatfs *fs, uint32 start_cluster);
|
||||
uint32 fatfs_count_free_clusters(struct fat_ctx *ctx, struct fatfs *fs);
|
||||
|
||||
#endif
|
||||
69
kernel/fs/fatfs/fat_types.h
Normal file
69
kernel/fs/fatfs/fat_types.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef __FAT_TYPES_H__
|
||||
#define __FAT_TYPES_H__
|
||||
|
||||
// Detect 64-bit compilation on GCC
|
||||
#if defined(__GNUC__) && defined(__SIZEOF_LONG__)
|
||||
#if __SIZEOF_LONG__ == 8
|
||||
#define FATFS_DEF_UINT32_AS_INT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// System specific types
|
||||
//-------------------------------------------------------------
|
||||
#ifndef FATFS_NO_DEF_TYPES
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
|
||||
// If compiling on a 64-bit machine, use int as 32-bits
|
||||
#ifdef FATFS_DEF_UINT32_AS_INT
|
||||
typedef unsigned int uint32;
|
||||
// Else for 32-bit machines & embedded systems, use long...
|
||||
#else
|
||||
typedef unsigned long uint32;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Endian Macros
|
||||
//-------------------------------------------------------------
|
||||
// FAT is little endian so big endian systems need to swap words
|
||||
|
||||
// Little Endian - No swap required
|
||||
#if FATFS_IS_LITTLE_ENDIAN == 1
|
||||
|
||||
#define FAT_HTONS(n) (n)
|
||||
#define FAT_HTONL(n) (n)
|
||||
|
||||
// Big Endian - Swap required
|
||||
#else
|
||||
|
||||
#define FAT_HTONS(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
|
||||
#define FAT_HTONL(n) (((((uint32)(n) & 0xFF)) << 24) | \
|
||||
((((uint32)(n) & 0xFF00)) << 8) | \
|
||||
((((uint32)(n) & 0xFF0000)) >> 8) | \
|
||||
((((uint32)(n) & 0xFF000000)) >> 24))
|
||||
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Structure Packing Compile Options
|
||||
//-------------------------------------------------------------
|
||||
#ifdef __GNUC__
|
||||
#define STRUCT_PACK
|
||||
#define STRUCT_PACK_BEGIN
|
||||
#define STRUCT_PACK_END
|
||||
#define STRUCT_PACKED __attribute__ ((packed))
|
||||
#else
|
||||
// Other compilers may require other methods of packing structures
|
||||
#define STRUCT_PACK
|
||||
#define STRUCT_PACK_BEGIN
|
||||
#define STRUCT_PACK_END
|
||||
#define STRUCT_PACKED
|
||||
#endif
|
||||
|
||||
#endif
|
||||
373
kernel/fs/fatfs/fat_write.c
Normal file
373
kernel/fs/fatfs/fat_write.c
Normal file
@ -0,0 +1,373 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// FAT16/32 File IO Library
|
||||
// V2.6
|
||||
// Ultra-Embedded.com
|
||||
// Copyright 2003 - 2012
|
||||
//
|
||||
// Email: admin@ultra-embedded.com
|
||||
//
|
||||
// License: GPL
|
||||
// If you would like a version with a more permissive license for use in
|
||||
// closed source commercial applications please contact me for details.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// This file is part of FAT File IO Library.
|
||||
//
|
||||
// FAT File IO Library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// FAT File IO Library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with FAT File IO Library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string.h>
|
||||
#include "fat_defs.h"
|
||||
#include "fat_access.h"
|
||||
#include "fat_table.h"
|
||||
#include "fat_write.h"
|
||||
#include "fat_string.h"
|
||||
#include "fat_misc.h"
|
||||
|
||||
#if FATFS_INC_WRITE_SUPPORT
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_add_free_space: Allocate another cluster of free space to the end
|
||||
// of a files cluster chain.
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_add_free_space(struct fat_ctx *ctx, struct fatfs *fs, uint32 *startCluster, uint32 clusters)
|
||||
{
|
||||
uint32 i;
|
||||
uint32 nextcluster;
|
||||
uint32 start = *startCluster;
|
||||
|
||||
// Set the next free cluster hint to unknown
|
||||
if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
|
||||
fatfs_set_fs_info_next_free_cluster(ctx, fs, FAT32_LAST_CLUSTER);
|
||||
|
||||
for (i=0;i<clusters;i++)
|
||||
{
|
||||
// Start looking for free clusters from the beginning
|
||||
if (fatfs_find_blank_cluster(ctx, fs, fs->rootdir_first_cluster, &nextcluster))
|
||||
{
|
||||
// Point last to this
|
||||
fatfs_fat_set_cluster(ctx, fs, start, nextcluster);
|
||||
|
||||
// Point this to end of file
|
||||
fatfs_fat_set_cluster(ctx, fs, nextcluster, FAT32_LAST_CLUSTER);
|
||||
|
||||
// Adjust argument reference
|
||||
start = nextcluster;
|
||||
if (i == 0)
|
||||
*startCluster = nextcluster;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_allocate_free_space: Add an ammount of free space to a file either from
|
||||
// 'startCluster' if newFile = false, or allocating a new start to the chain if
|
||||
// newFile = true.
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_allocate_free_space(struct fat_ctx *ctx, struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size)
|
||||
{
|
||||
uint32 clusterSize;
|
||||
uint32 clusterCount;
|
||||
uint32 nextcluster;
|
||||
|
||||
if (size==0)
|
||||
return 0;
|
||||
|
||||
// Set the next free cluster hint to unknown
|
||||
if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
|
||||
fatfs_set_fs_info_next_free_cluster(ctx, fs, FAT32_LAST_CLUSTER);
|
||||
|
||||
// Work out size and clusters
|
||||
clusterSize = fs->sectors_per_cluster * FAT_SECTOR_SIZE;
|
||||
clusterCount = (size / clusterSize);
|
||||
|
||||
// If any left over
|
||||
if (size-(clusterSize*clusterCount))
|
||||
clusterCount++;
|
||||
|
||||
// Allocated first link in the chain if a new file
|
||||
if (newFile)
|
||||
{
|
||||
if (!fatfs_find_blank_cluster(ctx, fs, fs->rootdir_first_cluster, &nextcluster))
|
||||
return 0;
|
||||
|
||||
// If this is all that is needed then all done
|
||||
if (clusterCount==1)
|
||||
{
|
||||
fatfs_fat_set_cluster(ctx, fs, nextcluster, FAT32_LAST_CLUSTER);
|
||||
*startCluster = nextcluster;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// Allocate from end of current chain (startCluster is end of chain)
|
||||
else
|
||||
nextcluster = *startCluster;
|
||||
|
||||
if (!fatfs_add_free_space(ctx, fs, &nextcluster, clusterCount))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_find_free_dir_offset: Find a free space in the directory for a new entry
|
||||
// which takes up 'entryCount' blocks (or allocate some more)
|
||||
//-----------------------------------------------------------------------------
|
||||
static int fatfs_find_free_dir_offset(struct fat_ctx *ctx, struct fatfs *fs, uint32 dirCluster, int entryCount, uint32 *pSector, uint8 *pOffset)
|
||||
{
|
||||
struct fat_dir_entry *directoryEntry;
|
||||
uint8 item=0;
|
||||
uint16 recordoffset = 0;
|
||||
uint8 i=0;
|
||||
int x=0;
|
||||
int possible_spaces = 0;
|
||||
int start_recorded = 0;
|
||||
|
||||
// No entries required?
|
||||
if (entryCount == 0)
|
||||
return 0;
|
||||
|
||||
// Main cluster following loop
|
||||
while (1)
|
||||
{
|
||||
// Read sector
|
||||
if (fatfs_sector_reader(ctx, fs, dirCluster, x++, 0))
|
||||
{
|
||||
// Analyse Sector
|
||||
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Create the multiplier for sector access
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// Overlay directory entry over buffer
|
||||
directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
|
||||
|
||||
// LFN Entry
|
||||
if (fatfs_entry_lfn_text(directoryEntry))
|
||||
{
|
||||
// First entry?
|
||||
if (possible_spaces == 0)
|
||||
{
|
||||
// Store start
|
||||
*pSector = x-1;
|
||||
*pOffset = item;
|
||||
start_recorded = 1;
|
||||
}
|
||||
|
||||
// Increment the count in-case the file turns
|
||||
// out to be deleted...
|
||||
possible_spaces++;
|
||||
}
|
||||
// SFN Entry
|
||||
else
|
||||
{
|
||||
// Has file been deleted?
|
||||
if (fs->currentsector.sector[recordoffset] == FILE_HEADER_DELETED)
|
||||
{
|
||||
// First entry?
|
||||
if (possible_spaces == 0)
|
||||
{
|
||||
// Store start
|
||||
*pSector = x-1;
|
||||
*pOffset = item;
|
||||
start_recorded = 1;
|
||||
}
|
||||
|
||||
possible_spaces++;
|
||||
|
||||
// We have found enough space?
|
||||
if (possible_spaces >= entryCount)
|
||||
return 1;
|
||||
|
||||
// Else continue counting until we find a valid entry!
|
||||
}
|
||||
// Is the file entry empty?
|
||||
else if (fs->currentsector.sector[recordoffset] == FILE_HEADER_BLANK)
|
||||
{
|
||||
// First entry?
|
||||
if (possible_spaces == 0)
|
||||
{
|
||||
// Store start
|
||||
*pSector = x-1;
|
||||
*pOffset = item;
|
||||
start_recorded = 1;
|
||||
}
|
||||
|
||||
// Increment the blank entries count
|
||||
possible_spaces++;
|
||||
|
||||
// We have found enough space?
|
||||
if (possible_spaces >= entryCount)
|
||||
return 1;
|
||||
}
|
||||
// File entry is valid
|
||||
else
|
||||
{
|
||||
// Reset all flags
|
||||
possible_spaces = 0;
|
||||
start_recorded = 0;
|
||||
}
|
||||
}
|
||||
} // End of for
|
||||
} // End of if
|
||||
// Run out of free space in the directory, allocate some more
|
||||
else
|
||||
{
|
||||
uint32 newCluster;
|
||||
|
||||
// Get a new cluster for directory
|
||||
if (!fatfs_find_blank_cluster(ctx, fs, fs->rootdir_first_cluster, &newCluster))
|
||||
return 0;
|
||||
|
||||
// Add cluster to end of directory tree
|
||||
if (!fatfs_fat_add_cluster_to_chain(ctx, fs, dirCluster, newCluster))
|
||||
return 0;
|
||||
|
||||
// Erase new directory cluster
|
||||
memset(fs->currentsector.sector, 0x00, FAT_SECTOR_SIZE);
|
||||
for (i=0;i<fs->sectors_per_cluster;i++)
|
||||
{
|
||||
if (!fatfs_write_sector(ctx, fs, newCluster, i, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If non of the name fitted on previous sectors
|
||||
if (!start_recorded)
|
||||
{
|
||||
// Store start
|
||||
*pSector = (x-1);
|
||||
*pOffset = 0;
|
||||
start_recorded = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
} // End of while loop
|
||||
|
||||
return 0;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// fatfs_add_file_entry: Add a directory entry to a location found by FindFreeOffset
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_add_file_entry(struct fat_ctx *ctx, struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir)
|
||||
{
|
||||
uint8 item=0;
|
||||
uint16 recordoffset = 0;
|
||||
uint8 i=0;
|
||||
uint32 x=0;
|
||||
int entryCount;
|
||||
struct fat_dir_entry shortEntry;
|
||||
int dirtySector = 0;
|
||||
|
||||
uint32 dirSector = 0;
|
||||
uint8 dirOffset = 0;
|
||||
int foundEnd = 0;
|
||||
|
||||
uint8 checksum;
|
||||
uint8 *pSname;
|
||||
|
||||
// No write access?
|
||||
if (!fs->disk_io.write_media)
|
||||
return 0;
|
||||
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
// How many LFN entries are required?
|
||||
// NOTE: We always request one LFN even if it would fit in a SFN!
|
||||
entryCount = fatfs_lfn_entries_required(filename);
|
||||
if (!entryCount)
|
||||
return 0;
|
||||
#else
|
||||
entryCount = 0;
|
||||
#endif
|
||||
|
||||
// Find space in the directory for this filename (or allocate some more)
|
||||
// NOTE: We need to find space for at least the LFN + SFN (or just the SFN if LFNs not supported).
|
||||
if (!fatfs_find_free_dir_offset(ctx, fs, dirCluster, entryCount + 1, &dirSector, &dirOffset))
|
||||
return 0;
|
||||
|
||||
// Generate checksum of short filename
|
||||
pSname = (uint8*)shortfilename;
|
||||
checksum = 0;
|
||||
for (i=11; i!=0; i--) checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *pSname++;
|
||||
|
||||
// Start from current sector where space was found!
|
||||
x = dirSector;
|
||||
|
||||
// Main cluster following loop
|
||||
while (1)
|
||||
{
|
||||
// Read sector
|
||||
if (fatfs_sector_reader(ctx, fs, dirCluster, x++, 0))
|
||||
{
|
||||
// Analyse Sector
|
||||
for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
|
||||
{
|
||||
// Create the multiplier for sector access
|
||||
recordoffset = FAT_DIR_ENTRY_SIZE * item;
|
||||
|
||||
// If the start position for the entry has been found
|
||||
if (foundEnd==0)
|
||||
if ( (dirSector==(x-1)) && (dirOffset==item) )
|
||||
foundEnd = 1;
|
||||
|
||||
// Start adding filename
|
||||
if (foundEnd)
|
||||
{
|
||||
if (entryCount==0)
|
||||
{
|
||||
// Short filename
|
||||
fatfs_sfn_create_entry(shortfilename, size, startCluster, &shortEntry, dir);
|
||||
|
||||
#if FATFS_INC_TIME_DATE_SUPPORT
|
||||
// Update create, access & modify time & date
|
||||
fatfs_update_timestamps(&shortEntry, 1, 1, 1);
|
||||
#endif
|
||||
|
||||
memcpy(&fs->currentsector.sector[recordoffset], &shortEntry, sizeof(shortEntry));
|
||||
|
||||
// Writeback
|
||||
return fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1);
|
||||
}
|
||||
#if FATFS_INC_LFN_SUPPORT
|
||||
else
|
||||
{
|
||||
entryCount--;
|
||||
|
||||
// Copy entry to directory buffer
|
||||
fatfs_filename_to_lfn(filename, &fs->currentsector.sector[recordoffset], entryCount, checksum);
|
||||
dirtySector = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} // End of if
|
||||
|
||||
// Write back to disk before loading another sector
|
||||
if (dirtySector)
|
||||
{
|
||||
if (!fs->disk_io.write_media(ctx, fs->currentsector.address, fs->currentsector.sector, 1))
|
||||
return 0;
|
||||
|
||||
dirtySector = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
} // End of while loop
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
16
kernel/fs/fatfs/fat_write.h
Normal file
16
kernel/fs/fatfs/fat_write.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __FAT_WRITE_H__
|
||||
#define __FAT_WRITE_H__
|
||||
|
||||
#include "fat_defs.h"
|
||||
#include "fat_opts.h"
|
||||
|
||||
struct fat_ctx;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Prototypes
|
||||
//-----------------------------------------------------------------------------
|
||||
int fatfs_add_file_entry(struct fat_ctx *ctx, struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir);
|
||||
int fatfs_add_free_space(struct fat_ctx *ctx, struct fatfs *fs, uint32 *startCluster, uint32 clusters);
|
||||
int fatfs_allocate_free_space(struct fat_ctx *ctx, struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size);
|
||||
|
||||
#endif
|
||||
225
kernel/fs/portfatfs/portfatfs.c
Normal file
225
kernel/fs/portfatfs/portfatfs.c
Normal file
@ -0,0 +1,225 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "fs/fatfs/fat_context.h"
|
||||
#include "fs/fatfs/fat_filelib.h"
|
||||
#include "sysdefs/fs.h"
|
||||
#include "vfs/vfs.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "std/string.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "util/util.h"
|
||||
#include "errors.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
// REF: https://github.com/ultraembedded/fat_io_lib/blob/master/examples/sd_card_generic/sd.c
|
||||
|
||||
int32_t fatfs_cleanup(struct VfsMountPoint *vmp) {
|
||||
fl_shutdown(&vmp->fs.fatfs.instance);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
void fatfs_vobj_cleanup(struct VfsObj *vobj) {
|
||||
if (vobj->extra != NULL) {
|
||||
fl_fclose(&vobj->vmp->fs.fatfs.instance, vobj->extra);
|
||||
}
|
||||
dlfree(vobj);
|
||||
}
|
||||
|
||||
int32_t fatfs_vobj_read(struct VfsObj *vobj, uint8_t *const buffer, size_t n, size_t off) {
|
||||
if (!(vobj->flags & VFS_FLAG_READ)) {
|
||||
return E_INVALIDOPER;
|
||||
}
|
||||
|
||||
spinlock_acquire(&vobj->spinlock);
|
||||
|
||||
int ok = fl_fseek(&vobj->vmp->fs.fatfs.instance, vobj->extra, off, SEEK_SET);
|
||||
if (ok < 0) {
|
||||
spinlock_release(&vobj->spinlock);
|
||||
return E_BADIO;
|
||||
}
|
||||
|
||||
ok = fl_fread(&vobj->vmp->fs.fatfs.instance, buffer, 1, n, vobj->extra);
|
||||
if (ok < 0) {
|
||||
spinlock_release(&vobj->spinlock);
|
||||
return E_BADIO;
|
||||
}
|
||||
|
||||
spinlock_release(&vobj->spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t fatfs_vobj_write(struct VfsObj *vobj, const uint8_t *const buffer, size_t n, size_t off) {
|
||||
if (!(vobj->flags & VFS_FLAG_WRITE)) {
|
||||
return E_INVALIDOPER;
|
||||
}
|
||||
|
||||
spinlock_acquire(&vobj->spinlock);
|
||||
|
||||
int ok = fl_fseek(&vobj->vmp->fs.fatfs.instance, vobj->extra, off, SEEK_SET);
|
||||
if (ok < 0) {
|
||||
spinlock_release(&vobj->spinlock);
|
||||
return E_BADIO;
|
||||
}
|
||||
|
||||
ok = fl_fwrite(&vobj->vmp->fs.fatfs.instance, buffer, 1, n, vobj->extra);
|
||||
if (ok < 0) {
|
||||
spinlock_release(&vobj->spinlock);
|
||||
return E_BADIO;
|
||||
}
|
||||
|
||||
spinlock_release(&vobj->spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
struct VfsObj *fatfs_open(struct VfsMountPoint *vmp, const char *path, uint32_t flags) {
|
||||
VfsObj *vobj = dlmalloc(sizeof(*vobj));
|
||||
if (vobj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(vobj, 0, sizeof(*vobj));
|
||||
spinlock_init(&vobj->spinlock);
|
||||
|
||||
char *mods = dlmalloc(4);
|
||||
memset(mods, 0, 4);
|
||||
|
||||
spinlock_acquire(&vmp->spinlock);
|
||||
|
||||
FatFs *fs = &vmp->fs.fatfs;
|
||||
|
||||
if ((flags & VFS_FLAG_READ) && !(flags & VFS_FLAG_WRITE) && !(flags & VFS_FLAG_MAKE)) {
|
||||
strcpy(mods, "rb");
|
||||
} else if (!(flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && !(flags & VFS_FLAG_MAKE)) {
|
||||
strcpy(mods, "wb");
|
||||
} else if ((flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && !(flags & VFS_FLAG_MAKE)) {
|
||||
strcpy(mods, "rb+");
|
||||
} else if (!(flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && (flags & VFS_FLAG_MAKE)) {
|
||||
strcpy(mods, "wb");
|
||||
} else if ((flags & VFS_FLAG_READ) && (flags & VFS_FLAG_WRITE) && (flags & VFS_FLAG_MAKE)) {
|
||||
strcpy(mods, "wb+");
|
||||
}
|
||||
|
||||
void *f = fl_fopen(&fs->instance, path, mods);
|
||||
|
||||
dlfree(mods);
|
||||
|
||||
if (f == NULL) {
|
||||
dlfree(vobj);
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vobj->flags = flags;
|
||||
vobj->extra = f;
|
||||
vobj->vmp = vmp;
|
||||
vobj->cleanup = &fatfs_vobj_cleanup;
|
||||
vobj->read = &fatfs_vobj_read;
|
||||
vobj->write = &fatfs_vobj_write;
|
||||
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return vobj;
|
||||
}
|
||||
|
||||
int32_t fatfs_stat(struct VfsMountPoint *vmp, const char *path, FsStat *statbuf) {
|
||||
spinlock_acquire(&vmp->spinlock);
|
||||
|
||||
if (fl_is_dir(&vmp->fs.fatfs.instance, path)) {
|
||||
FL_DIR dirstat;
|
||||
if (fl_opendir(&vmp->fs.fatfs.instance, path, &dirstat) == NULL) {
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
statbuf->type = FSSTAT_DIR;
|
||||
statbuf->size = 0;
|
||||
fl_dirent dirent;
|
||||
while (fl_readdir(&vmp->fs.fatfs.instance, &dirstat, &dirent) == 0) {
|
||||
statbuf->size++;
|
||||
}
|
||||
fl_closedir(&vmp->fs.fatfs.instance, &dirstat);
|
||||
} else {
|
||||
FL_FILE *f = fl_fopen(&vmp->fs.fatfs.instance, path, "r");
|
||||
statbuf->type = FSSTAT_FILE;
|
||||
statbuf->size = f->filelength;
|
||||
fl_fclose(&vmp->fs.fatfs.instance, f);
|
||||
}
|
||||
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t fatfs_fetchdirent(struct VfsMountPoint *vmp, const char *path, FsDirent *direntbuf, size_t idx) {
|
||||
spinlock_acquire(&vmp->spinlock);
|
||||
|
||||
FL_DIR dirstat;
|
||||
FL_DIR *d = fl_opendir(&vmp->fs.fatfs.instance, path, &dirstat);
|
||||
if (d == NULL) {
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return E_BADIO;
|
||||
}
|
||||
|
||||
fl_dirent dirent;
|
||||
size_t i = 0;
|
||||
while (fl_readdir(&vmp->fs.fatfs.instance, d, &dirent) == 0) {
|
||||
if (i == idx) {
|
||||
direntbuf->stat.type = dirent.is_dir ? FSSTAT_DIR : FSSTAT_FILE;
|
||||
direntbuf->stat.size = dirent.is_dir ? 0 : dirent.size;
|
||||
strncpy(direntbuf->name, dirent.filename, sizeof(direntbuf->name));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
fl_closedir(&vmp->fs.fatfs.instance, d);
|
||||
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t fatfs_mkdir(struct VfsMountPoint *vmp, const char *path) {
|
||||
spinlock_acquire(&vmp->spinlock);
|
||||
int err = fl_createdirectory(&vmp->fs.fatfs.instance, path);
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return err == 0 ? E_OK : E_BADIO;
|
||||
}
|
||||
|
||||
int32_t fatfs_delete(struct VfsMountPoint *vmp, const char *path) {
|
||||
spinlock_acquire(&vmp->spinlock);
|
||||
int err = fl_remove(&vmp->fs.fatfs.instance, path);
|
||||
spinlock_release(&vmp->spinlock);
|
||||
return err == 0 ? E_OK : E_BADIO;
|
||||
}
|
||||
|
||||
int portfatfs_diskio_read(struct fat_ctx *ctx, uint32_t sector, uint8_t *buffer, uint32_t sector_count) {
|
||||
VfsMountPoint *vmp = ctx->extra;
|
||||
|
||||
if (sector_count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t byteaddr = (uint64_t)sector * FAT_SECTOR_SIZE;
|
||||
ptrdiff_t sector1 = byteaddr / vmp->backingsd->sectorsize;
|
||||
ptrdiff_t sector_off = byteaddr % vmp->backingsd->sectorsize;
|
||||
|
||||
int32_t ret = vmp->backingsd->read(vmp->backingsd, (uint8_t *const)buffer, sector1, sector_off, sector_count * FAT_SECTOR_SIZE);
|
||||
if (ret != E_OK) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int portfatfs_diskio_write(struct fat_ctx *ctx, uint32_t sector, uint8_t *buffer, uint32_t sector_count) {
|
||||
VfsMountPoint *vmp = ctx->extra;
|
||||
|
||||
if (sector_count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t byteaddr = (uint64_t)sector * FAT_SECTOR_SIZE;
|
||||
ptrdiff_t sector1 = byteaddr / vmp->backingsd->sectorsize;
|
||||
ptrdiff_t sector_off = byteaddr % vmp->backingsd->sectorsize;
|
||||
|
||||
int32_t ret = vmp->backingsd->write(vmp->backingsd, (const uint8_t *const)buffer, sector1, sector_off, sector_count * FAT_SECTOR_SIZE);
|
||||
if (ret != E_OK) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
26
kernel/fs/portfatfs/portfatfs.h
Normal file
26
kernel/fs/portfatfs/portfatfs.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef FS_PORTFATFS_PORTFATFS_H_
|
||||
#define FS_PORTFATFS_PORTFATFS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "fs/fatfs/fat_context.h"
|
||||
#include "sysdefs/fs.h"
|
||||
|
||||
struct VfsMountPoint;
|
||||
struct VfsObj;
|
||||
|
||||
typedef struct {
|
||||
struct fat_ctx instance;
|
||||
} FatFs;
|
||||
|
||||
int32_t fatfs_cleanup(struct VfsMountPoint *vmp);
|
||||
struct VfsObj *fatfs_open(struct VfsMountPoint *vmp, const char *path, uint32_t flags);
|
||||
int32_t fatfs_stat(struct VfsMountPoint *vmp, const char *path, FsStat *statbuf);
|
||||
int32_t fatfs_fetchdirent(struct VfsMountPoint *vmp, const char *path, FsDirent *direntbuf, size_t idx);
|
||||
int32_t fatfs_mkdir(struct VfsMountPoint *vmp, const char *path);
|
||||
int32_t fatfs_delete(struct VfsMountPoint *vmp, const char *path);
|
||||
|
||||
int portfatfs_diskio_read(struct fat_ctx *ctx, uint32_t sector, uint8_t *buffer, uint32_t sector_count);
|
||||
int portfatfs_diskio_write(struct fat_ctx *ctx, uint32_t sector, uint8_t *buffer, uint32_t sector_count);
|
||||
|
||||
#endif // FS_PORTFATFS_PORTFATFS_H_
|
||||
@ -2,18 +2,14 @@
|
||||
#include <stdbool.h>
|
||||
#include "fs/littlefs/lfs.h"
|
||||
#include "vfs/vfs.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "std/string.h"
|
||||
#include "errors.h"
|
||||
#include "kprintf.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "hal/hal.h"
|
||||
|
||||
int32_t littlefs_cleanup(struct VfsMountPoint *vmp) {
|
||||
dlfree((void *)vmp->fs.littlefs.instance.cfg);
|
||||
int32_t err = vmp->backingsd->cleanup(vmp->backingsd);
|
||||
if (err != E_OK) {
|
||||
return err;
|
||||
}
|
||||
err = lfs_unmount(&vmp->fs.littlefs.instance);
|
||||
int32_t err = lfs_unmount(&vmp->fs.littlefs.instance);
|
||||
if (err < 0) { return E_BADIO; }
|
||||
return E_OK;
|
||||
}
|
||||
@ -132,7 +128,7 @@ struct VfsObj *littlefs_open(struct VfsMountPoint *vmp, const char *path, uint32
|
||||
if (vobj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
hal_memset(vobj, 0, sizeof(*vobj));
|
||||
memset(vobj, 0, sizeof(*vobj));
|
||||
spinlock_init(&vobj->spinlock);
|
||||
|
||||
int lfs_flags = 0;
|
||||
@ -169,7 +165,6 @@ struct VfsObj *littlefs_open(struct VfsMountPoint *vmp, const char *path, uint32
|
||||
|
||||
vobj->flags = flags;
|
||||
vobj->extra = file;
|
||||
vobj->extrasize = sizeof(*file);
|
||||
vobj->vmp = vmp;
|
||||
vobj->cleanup = &littlefs_vobj_cleanup;
|
||||
vobj->read = &littlefs_vobj_read;
|
||||
@ -214,7 +209,7 @@ int32_t littlefs_fetchdirent(struct VfsMountPoint *vmp, const char *path, FsDire
|
||||
direntbuf->stat.type = FSSTAT_DIR;
|
||||
}
|
||||
|
||||
hal_memcpy(direntbuf->name, entinfo.name, sizeof(direntbuf->name));
|
||||
memcpy(direntbuf->name, entinfo.name, sizeof(direntbuf->name));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
#ifndef KERNEL_HAL_HAL_H_
|
||||
#define KERNEL_HAL_HAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
__attribute__((noreturn)) void hal_hang(void);
|
||||
|
||||
void hal_init(void);
|
||||
void hal_intr_disable(void);
|
||||
void hal_intr_enable(void);
|
||||
void *hal_memset(void *p, int c, size_t n);
|
||||
void *hal_memcpy(void *dst, const void *src, size_t n);
|
||||
size_t hal_strlen(char *s);
|
||||
int hal_memcmp(const void *s1, const void *s2, int len);
|
||||
int hal_strcmp(const char *a, const char *b);
|
||||
size_t hal_strcspn(const char *s, const char *reject);
|
||||
size_t hal_strspn(const char *s, const char *accept);
|
||||
char *hal_strcpy(char *dest, const char *src);
|
||||
char *hal_strchr(const char *s, int c);
|
||||
char *hal_strstr(const char *str, const char *substring);
|
||||
char *hal_string_combine(char *dest, const char *src);
|
||||
void hal_wait(uint32_t ms);
|
||||
int32_t hal_randnum(void);
|
||||
|
||||
#define HAL_PAGE_SIZE 0x1000
|
||||
#include "x86_64/vmm.h"
|
||||
#include "x86_64/switch.h"
|
||||
#include "x86_64/paging.h"
|
||||
#include "x86_64/intr.h"
|
||||
#include "x86_64/io.h"
|
||||
#include "x86_64/gdt.h"
|
||||
|
||||
#endif // KERNEL_HAL_HAL_H_
|
||||
@ -1,152 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "hal.h"
|
||||
|
||||
void *hal_memset(void *p, int c, size_t n) {
|
||||
char *cp = p;
|
||||
for (size_t i = 0; i < n; i++) cp[i] = c;
|
||||
return p;
|
||||
}
|
||||
|
||||
void *hal_memcpy(void *dst, const void *src, size_t n) {
|
||||
char *a = dst;
|
||||
const char *b = src;
|
||||
for (size_t i = 0; i < n; i++) a[i] = b[i];
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t hal_strlen(char *s) {
|
||||
char *s2;
|
||||
for (s2 = s; *s2; ++s2);
|
||||
return (s2 - s);
|
||||
}
|
||||
|
||||
// https://aticleworld.com/memcmp-in-c/
|
||||
int hal_memcmp(const void *s1, const void *s2, int len)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)s1;
|
||||
unsigned char *q = (unsigned char *)s2;
|
||||
int charCompareStatus = 0;
|
||||
//If both pointer pointing same memory block
|
||||
if (s1 == s2)
|
||||
{
|
||||
return charCompareStatus;
|
||||
}
|
||||
while (len > 0)
|
||||
{
|
||||
if (*p != *q)
|
||||
{ //compare the mismatching character
|
||||
charCompareStatus = (*p >*q)?1:-1;
|
||||
break;
|
||||
}
|
||||
len--;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
return charCompareStatus;
|
||||
}
|
||||
|
||||
int hal_strcmp(const char *a, const char *b) {
|
||||
while (*a && (*a == *b)) {
|
||||
a++, b++;
|
||||
}
|
||||
return (unsigned char)*a - (unsigned char)*b;
|
||||
}
|
||||
|
||||
size_t hal_strcspn(const char *s, const char *reject) {
|
||||
size_t count = 0;
|
||||
for (; *s != '\0'; ++s) {
|
||||
const char *r = reject;
|
||||
while (*r != '\0') {
|
||||
if (*s == *r) {
|
||||
return count;
|
||||
}
|
||||
r++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t hal_strspn(const char *s, const char *accept) {
|
||||
size_t count = 0;
|
||||
for (; *s != '\0'; ++s) {
|
||||
const char *a = accept;
|
||||
int matched = 0;
|
||||
while (*a != '\0') {
|
||||
if (*s == *a) {
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
if (!matched) {
|
||||
return count;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
char *hal_strcpy(char *dest, const char *src) {
|
||||
char *d = dest;
|
||||
while ((*d++ = *src++) != '\0') {
|
||||
;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *hal_strchr(const char *s, int c) {
|
||||
char ch = (char)c;
|
||||
while (*s != '\0') {
|
||||
if (*s == ch) {
|
||||
return (char *)s;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (ch == '\0') {
|
||||
return (char *)s;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *hal_strstr(const char *str, const char *substring)
|
||||
{
|
||||
const char *a;
|
||||
const char *b;
|
||||
|
||||
b = substring;
|
||||
|
||||
if (*b == 0) {
|
||||
return (char *) str;
|
||||
}
|
||||
|
||||
for ( ; *str != 0; str += 1) {
|
||||
if (*str != *b) {
|
||||
continue;
|
||||
}
|
||||
|
||||
a = str;
|
||||
while (1) {
|
||||
if (*b == 0) {
|
||||
return (char *) str;
|
||||
}
|
||||
if (*a++ != *b++) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
b = substring;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *hal_string_combine(char *dest, const char *src) {
|
||||
size_t i, j;
|
||||
for(i = 0; dest[i] != '\0'; i++);
|
||||
for(j = 0; src[j] != '\0'; j++) {
|
||||
dest[i+j] = src[j];
|
||||
}
|
||||
dest[i+j] = '\0';
|
||||
return dest;
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "hal/hal.h"
|
||||
#include "kprintf.h"
|
||||
#include "gdt.h"
|
||||
#include "intr.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
|
||||
void hal_init(void) {
|
||||
gdt_init();
|
||||
intr_init();
|
||||
pic_init();
|
||||
pit_init();
|
||||
hal_intr_disable();
|
||||
}
|
||||
|
||||
__attribute__((noreturn)) void hal_hang(void) {
|
||||
for(;;) {
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void hal_wait(uint32_t ms) {
|
||||
pit_wait(ms);
|
||||
}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
.global hal_loadpd
|
||||
hal_loadpd:
|
||||
mov %rdi, %cr3
|
||||
retq
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef HAL_PAGING_H_
|
||||
#define HAL_PAGING_H_
|
||||
|
||||
void hal_loadpd(PgTable *cr3);
|
||||
|
||||
#endif // HAL_PAGING_H_
|
||||
@ -1,22 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "pic.h"
|
||||
#include "io.h"
|
||||
#include "intr.h"
|
||||
|
||||
void pic_init(void) {
|
||||
io_out8(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
io_out8(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
|
||||
io_out8(PIC1_DATA, INTR_IRQBASE);
|
||||
io_out8(PIC2_DATA, INTR_IRQBASE+8);
|
||||
|
||||
io_out8(PIC1_DATA, 2);
|
||||
io_out8(PIC2_DATA, 2);
|
||||
|
||||
io_out8(PIC1_DATA, ICW4_8086);
|
||||
io_out8(PIC2_DATA, ICW4_8086);
|
||||
|
||||
io_out8(PIC1_DATA, 0);
|
||||
io_out8(PIC2_DATA, 0);
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
#ifndef HAL_PIC_H_
|
||||
#define HAL_PIC_H_
|
||||
|
||||
#define PIC1_CMD 0x0020
|
||||
#define PIC1_DATA 0x0021
|
||||
#define PIC2_CMD 0x00A0
|
||||
#define PIC2_DATA 0x00A1
|
||||
|
||||
#define PIC_EOI 0x20
|
||||
|
||||
#define ICW1_ICW4 0x01
|
||||
#define ICW1_SINGLE 0x02
|
||||
#define ICW1_ADI 0x04
|
||||
#define ICW1_LTIM 0x08
|
||||
#define ICW1_INIT 0x10
|
||||
|
||||
#define ICW4_8086 0x01
|
||||
#define ICW4_AUTO 0x02
|
||||
#define ICW4_BUFSLAVE 0x04
|
||||
#define ICW4_BUFMASTER 0x0C
|
||||
#define ICW4_SFNM 0x10
|
||||
|
||||
void pic_init(void);
|
||||
|
||||
#endif // HAL_PIC_H_
|
||||
@ -1,11 +0,0 @@
|
||||
#ifndef HAL_PIT_H_
|
||||
#define HAL_PIT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern volatile uint32_t PIT_TICKS;
|
||||
|
||||
void pit_init(void);
|
||||
void pit_wait(uint32_t ms);
|
||||
|
||||
#endif // HAL_PIT_H_
|
||||
@ -1,12 +0,0 @@
|
||||
#include "regs.S"
|
||||
|
||||
.global hal_switchproc
|
||||
hal_switchproc:
|
||||
testq %rsi, %rsi
|
||||
je 1f
|
||||
movq %rsi, %cr3
|
||||
1:
|
||||
mov %rdi, %rsp
|
||||
_pop_regs
|
||||
add $0x10, %rsp
|
||||
iretq
|
||||
@ -1,6 +0,0 @@
|
||||
#ifndef HAL_SWITCH_H_
|
||||
#define HAL_SWITCH_H_
|
||||
|
||||
extern void hal_switchproc(void *newsp, PgTable *cr3);
|
||||
|
||||
#endif // HAL_SWITCH_H_
|
||||
@ -1,128 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "vmm.h"
|
||||
#include "hal/hal.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "pmm/pmm.h"
|
||||
#include "paging.h"
|
||||
#include "proc/proc.h"
|
||||
#include "kprintf.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
|
||||
uint64_t KERNEL_CR3 = 0;
|
||||
SpinLock spinlock;
|
||||
|
||||
uint64_t hal_vmm_current_cr3(void) {
|
||||
uint64_t cr3;
|
||||
asm volatile("mov %%cr3, %0" : "=r"(cr3));
|
||||
return cr3;
|
||||
}
|
||||
|
||||
PgIndex hal_vmm_pageindex(uint64_t vaddr) {
|
||||
PgIndex ret;
|
||||
|
||||
ret.pml4 = (vaddr >> 39) & 0x1ff;
|
||||
ret.pml3 = (vaddr >> 30) & 0x1ff;
|
||||
ret.pml2 = (vaddr >> 21) & 0x1ff;
|
||||
ret.pml1 = (vaddr >> 12) & 0x1ff;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t *hal_vmm_nexttable(uint64_t *table, uint64_t ent, bool alloc) {
|
||||
uint64_t entry = table[ent];
|
||||
uint64_t phys;
|
||||
if (entry & HAL_PG_PRESENT) {
|
||||
phys = entry & ~0xFFFULL;
|
||||
} else {
|
||||
if (!alloc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *newphys = pmm_alloc(1);
|
||||
phys = (uint64_t)newphys;
|
||||
hal_memset(VIRT(phys), 0, HAL_PAGE_SIZE);
|
||||
table[ent] = phys | HAL_PG_USER | HAL_PG_RW | HAL_PG_PRESENT;
|
||||
}
|
||||
return (uint64_t *)((uint8_t *)VIRT(phys));
|
||||
}
|
||||
|
||||
void hal_vmm_map_page(uint64_t cr3phys, uint64_t virtaddr, uint64_t physaddr, uint32_t flags) {
|
||||
uint64_t *pml4 = (uint64_t *)VIRT(cr3phys);
|
||||
PgIndex pi = hal_vmm_pageindex(virtaddr);
|
||||
|
||||
uint64_t *pml3 = hal_vmm_nexttable(pml4, pi.pml4, true);
|
||||
uint64_t *pml2 = hal_vmm_nexttable(pml3, pi.pml3, true);
|
||||
uint64_t *pml1 = hal_vmm_nexttable(pml2, pi.pml2, true);
|
||||
uint64_t *pte = &pml1[pi.pml1];
|
||||
|
||||
*pte = (physaddr & ~0xFFFULL) | ((uint64_t)flags & 0x7ULL);
|
||||
}
|
||||
|
||||
void hal_vmm_unmap_page(uint64_t cr3phys, uint64_t virtaddr) {
|
||||
uint64_t *pml4 = (uint64_t *)VIRT(cr3phys);
|
||||
PgIndex pi = hal_vmm_pageindex(virtaddr);
|
||||
|
||||
uint64_t *pml3 = hal_vmm_nexttable(pml4, pi.pml4, false);
|
||||
uint64_t *pml2 = hal_vmm_nexttable(pml3, pi.pml3, false);
|
||||
uint64_t *pml1 = hal_vmm_nexttable(pml2, pi.pml2, false);
|
||||
uint64_t *pte = &pml1[pi.pml1];
|
||||
|
||||
*pte &= ~HAL_PG_PRESENT;
|
||||
}
|
||||
|
||||
void hal_vmm_map_range(uint64_t cr3phys, void *virtstart, void *physstart, size_t size, uint32_t flags) {
|
||||
if (size % HAL_PAGE_SIZE != 0 || (uint64_t)virtstart % HAL_PAGE_SIZE != 0 || (uint64_t)physstart % HAL_PAGE_SIZE != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
spinlock_acquire(&spinlock);
|
||||
uint8_t *vaddr = (uint8_t *)virtstart;
|
||||
uint8_t *paddr = (uint8_t *)physstart;
|
||||
uint8_t *end = (uint8_t *)virtstart + size;
|
||||
for (; vaddr < end; vaddr += HAL_PAGE_SIZE, paddr += HAL_PAGE_SIZE) {
|
||||
hal_vmm_map_page(cr3phys, (uint64_t)vaddr, (uint64_t)paddr, flags);
|
||||
}
|
||||
spinlock_release(&spinlock);
|
||||
}
|
||||
|
||||
void hal_vmm_unmap_range(uint64_t cr3phys, void *virtstart, void *physstart, size_t size) {
|
||||
if (size % HAL_PAGE_SIZE != 0 || (uint64_t)virtstart % HAL_PAGE_SIZE != 0 || (uint64_t)physstart % HAL_PAGE_SIZE != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
spinlock_acquire(&spinlock);
|
||||
uint8_t *vaddr = (uint8_t *)virtstart;
|
||||
uint8_t *end = vaddr + size;
|
||||
|
||||
for (; vaddr < end; vaddr += HAL_PAGE_SIZE) {
|
||||
hal_vmm_unmap_page(cr3phys, (uint64_t)vaddr);
|
||||
}
|
||||
spinlock_release(&spinlock);
|
||||
}
|
||||
|
||||
void hal_vmm_map_kern(uint64_t targetcr3) {
|
||||
uint64_t *kcr3 = (uint64_t *)VIRT(KERNEL_CR3);
|
||||
uint64_t *cr3 = (uint64_t *)VIRT(targetcr3);
|
||||
for (size_t i = 0; i < 512; i++) {
|
||||
cr3[i] = kcr3[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t hal_vmm_userproc_pml4_phys(void) {
|
||||
uint8_t *cr3phys = pmm_alloc(1);
|
||||
uint64_t phys = (uint64_t)cr3phys;
|
||||
hal_memset(VIRT(phys), 0, HAL_PAGE_SIZE);
|
||||
|
||||
uint64_t *kcr3 = (uint64_t *)VIRT(KERNEL_CR3);
|
||||
uint64_t *pml4 = (uint64_t *)VIRT(phys);
|
||||
for (size_t i = 256; i < 512; i++) {
|
||||
pml4[i] = kcr3[i];
|
||||
}
|
||||
return phys;
|
||||
}
|
||||
|
||||
void hal_vmm_init(void) {
|
||||
spinlock_init(&spinlock);
|
||||
KERNEL_CR3 = hal_vmm_current_cr3();
|
||||
}
|
||||
@ -4,8 +4,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "hal/hal.h"
|
||||
#include "util/util.h"
|
||||
#include "std/string.h"
|
||||
|
||||
#define HSHTB_FNV32_OFF 0x811c9dc5u
|
||||
#define HSHTB_FNV32_PRIME 0x01000193u
|
||||
@ -32,7 +32,7 @@ enum {
|
||||
#define HSHTB_ALLOC(tb, keyfield, k, out) \
|
||||
do { \
|
||||
size_t __len = __HSHTB_ARRAY_LEN(tb); \
|
||||
uint32_t __h = hshtb_fnv32((k), hal_strlen((k))); \
|
||||
uint32_t __h = hshtb_fnv32((k), strlen((k))); \
|
||||
size_t __idx = __h % __len; \
|
||||
size_t __start = __idx; \
|
||||
typeof(&(tb)[0]) __tomb = NULL; \
|
||||
@ -40,13 +40,13 @@ enum {
|
||||
do { \
|
||||
if ((tb)[__idx]._hshtbstate == HSHTB_EMPTY) { \
|
||||
typeof(&(tb)[0]) __slot = __tomb ? __tomb : &(tb)[__idx]; \
|
||||
hal_memset(__slot, 0, sizeof(*__slot)); \
|
||||
memset(__slot, 0, sizeof(*__slot)); \
|
||||
__slot->_hshtbstate = HSHTB_TAKEN; \
|
||||
hal_memcpy(__slot->keyfield, (k), MIN(sizeof(__slot->keyfield) - 1, hal_strlen((k)))); \
|
||||
memcpy(__slot->keyfield, (k), MIN(sizeof(__slot->keyfield) - 1, strlen((k)))); \
|
||||
(out) = __slot; \
|
||||
break; \
|
||||
} \
|
||||
if ((tb)[__idx]._hshtbstate == HSHTB_TAKEN && hal_strcmp((tb)[__idx].keyfield, (k)) == 0) { \
|
||||
if ((tb)[__idx]._hshtbstate == HSHTB_TAKEN && strcmp((tb)[__idx].keyfield, (k)) == 0) { \
|
||||
(out) = &(tb)[__idx]; \
|
||||
break; \
|
||||
} \
|
||||
@ -60,7 +60,7 @@ enum {
|
||||
#define HSHTB_GET(tb, keyfield, k, out) \
|
||||
do { \
|
||||
size_t __len = __HSHTB_ARRAY_LEN(tb); \
|
||||
uint32_t __h = hshtb_fnv32((k), hal_strlen((k))); \
|
||||
uint32_t __h = hshtb_fnv32((k), strlen((k))); \
|
||||
size_t __idx = __h % __len; \
|
||||
size_t __start = __idx; \
|
||||
(out) = NULL; \
|
||||
@ -68,7 +68,7 @@ enum {
|
||||
if ((tb)[__idx]._hshtbstate == HSHTB_EMPTY) { \
|
||||
break; \
|
||||
} \
|
||||
if ((tb)[__idx]._hshtbstate == HSHTB_TAKEN && hal_strcmp((tb)[__idx].keyfield, (k)) == 0) { \
|
||||
if ((tb)[__idx]._hshtbstate == HSHTB_TAKEN && strcmp((tb)[__idx].keyfield, (k)) == 0) { \
|
||||
(out) = &(tb)[__idx]; \
|
||||
break; \
|
||||
} \
|
||||
|
||||
@ -1,35 +1,57 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "intr.h"
|
||||
#include "io.h"
|
||||
#include "gdt.h"
|
||||
#include "hal/hal.h"
|
||||
#include "kprintf.h"
|
||||
#include "intr/intr.h"
|
||||
#include "intr/pic.h"
|
||||
#include "intr/pit.h"
|
||||
#include "io/io.h"
|
||||
#include "cpu/gdt.h"
|
||||
#include "compiler/attr.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
#include "proc/proc.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include "errors.h"
|
||||
#include "ipc/pipe/pipe.h"
|
||||
#include "rbuf/rbuf.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "util/util.h"
|
||||
#include "cpu/hang.h"
|
||||
#include "kprintf.h"
|
||||
#include "errors.h"
|
||||
|
||||
typedef struct IntrHandler {
|
||||
struct IntrHandler *next;
|
||||
void (*fn)(void);
|
||||
void (*fn)(IntrStackFrame *frame);
|
||||
int irq;
|
||||
} IntrHandler;
|
||||
|
||||
IntrHandler *INTR_HANDLERS = NULL;
|
||||
SpinLock INTR_HANDLERS_SPINLOCK;
|
||||
|
||||
void intr_attchhandler(void (*fn)(void), int irq) {
|
||||
void intr_attchhandler(void (*fn)(IntrStackFrame *frame), int irq) {
|
||||
IntrHandler *ih = dlmalloc(sizeof(*ih));
|
||||
ih->fn = fn;
|
||||
ih->irq = irq;
|
||||
spinlock_acquire(&INTR_HANDLERS_SPINLOCK);
|
||||
LL_APPEND(INTR_HANDLERS, ih);
|
||||
spinlock_release(&INTR_HANDLERS_SPINLOCK);
|
||||
}
|
||||
|
||||
int32_t intr_dttchhandler(int irq) {
|
||||
IntrHandler *ih = NULL;
|
||||
|
||||
spinlock_acquire(&INTR_HANDLERS_SPINLOCK);
|
||||
|
||||
LL_FINDPROP(INTR_HANDLERS, ih, irq, irq);
|
||||
|
||||
if (ih == NULL) {
|
||||
spinlock_release(&INTR_HANDLERS_SPINLOCK);
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
LL_REMOVE(INTR_HANDLERS, ih);
|
||||
spinlock_release(&INTR_HANDLERS_SPINLOCK);
|
||||
|
||||
dlfree(ih);
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
typedef struct BackTraceFrame {
|
||||
@ -37,7 +59,7 @@ typedef struct BackTraceFrame {
|
||||
uint64_t rip;
|
||||
} BackTraceFrame;
|
||||
|
||||
void backtrace(BackTraceFrame *bt) {
|
||||
void intr_backtrace(BackTraceFrame *bt) {
|
||||
kprintf("Backtrace:\n");
|
||||
for (size_t frame = 0; bt; frame++) {
|
||||
kprintf(" %zu: 0x%lx\n", frame, bt->rip);
|
||||
@ -45,11 +67,11 @@ void backtrace(BackTraceFrame *bt) {
|
||||
}
|
||||
}
|
||||
|
||||
void hal_intr_disable(void) {
|
||||
void intr_disable(void) {
|
||||
asm volatile("cli");
|
||||
}
|
||||
|
||||
void hal_intr_enable(void) {
|
||||
void intr_enable(void) {
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
@ -104,6 +126,8 @@ static const char *exceptions[] = {
|
||||
};
|
||||
|
||||
void intr_init(void) {
|
||||
spinlock_init(&INTR_HANDLERS_SPINLOCK);
|
||||
|
||||
#define MKINTR(N) \
|
||||
extern void intr_vec##N(void); \
|
||||
idt_setentry(N, (uint64_t)&intr_vec##N, 0x8E);
|
||||
@ -160,6 +184,8 @@ void intr_init(void) {
|
||||
idt_setentry(0x80, (uint64_t)&intr_vec128, 0xEE);
|
||||
|
||||
idt_init();
|
||||
intr_pic_init();
|
||||
intr_pit_init();
|
||||
}
|
||||
|
||||
void intr_dumpframe(IntrStackFrame *frame) {
|
||||
@ -185,7 +211,7 @@ void intr_dumpframe(IntrStackFrame *frame) {
|
||||
);
|
||||
}
|
||||
|
||||
void hal_syscalldispatch(IntrStackFrame *frame) {
|
||||
void intr_syscalldispatch(IntrStackFrame *frame) {
|
||||
uint64_t sysnum = frame->regs.rax;
|
||||
if (sysnum < SYSCALLS_MAX) {
|
||||
SyscallFn fn = SYSCALL_TABLE[sysnum];
|
||||
@ -194,7 +220,7 @@ void hal_syscalldispatch(IntrStackFrame *frame) {
|
||||
return;
|
||||
}
|
||||
uint64_t calling_proc_pid = PROCS.current->pid;
|
||||
hal_intr_enable();
|
||||
intr_enable();
|
||||
int32_t ret = fn(frame, calling_proc_pid, frame->regs.rdi, frame->regs.rsi, frame->regs.rdx,
|
||||
frame->regs.r10, frame->regs.r8, frame->regs.r9);
|
||||
|
||||
@ -205,43 +231,35 @@ void hal_syscalldispatch(IntrStackFrame *frame) {
|
||||
}
|
||||
}
|
||||
|
||||
void intr_eoi() {
|
||||
io_out8(PIC2_CMD, PIC_EOI);
|
||||
io_out8(PIC1_CMD, PIC_EOI);
|
||||
}
|
||||
|
||||
void intr_handleintr(IntrStackFrame *frame) {
|
||||
if (frame->trapnum <= 31) {
|
||||
kprintf("ERROR %s, 0x%lX\n", exceptions[frame->trapnum], frame->errnum);
|
||||
intr_dumpframe(frame);
|
||||
backtrace((BackTraceFrame *)frame->regs.rbp);
|
||||
intr_backtrace((BackTraceFrame *)frame->regs.rbp);
|
||||
if (frame->cs == (UCODE | 0x3)) {
|
||||
kprintf("killed pid %ld %s\n", PROCS.current->pid, PROCS.current->name);
|
||||
proc_killself();
|
||||
proc_sched((void *)frame);
|
||||
} else {
|
||||
kprintf("Kernel error :(\n");
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
} else if (frame->trapnum >= 32 && frame->trapnum <= 47) {
|
||||
switch (frame->trapnum) {
|
||||
case INTR_IRQBASE+0:
|
||||
if (frame->trapnum == INTR_IRQBASE+0) {
|
||||
PIT_TICKS++;
|
||||
intr_eoi();
|
||||
intr_pic_eoi(frame->trapnum >= 40);
|
||||
proc_sched((void *)frame);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
IntrHandler *ih, *ihtmp;
|
||||
LL_FOREACH_SAFE(INTR_HANDLERS, ih, ihtmp) {
|
||||
if ((uint64_t)ih->irq == frame->trapnum) {
|
||||
ih->fn();
|
||||
ih->fn(frame);
|
||||
}
|
||||
}
|
||||
intr_eoi();
|
||||
break;
|
||||
intr_pic_eoi(frame->trapnum >= 40);
|
||||
}
|
||||
} else if (frame->trapnum == 0x80) {
|
||||
hal_syscalldispatch(frame);
|
||||
intr_syscalldispatch(frame);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
#ifndef HAL_INTR_H_
|
||||
#define HAL_INTR_H_
|
||||
#ifndef INTR_INTR_H_
|
||||
#define INTR_INTR_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "compiler/attr.h"
|
||||
|
||||
#define INTR_IRQBASE 0x20
|
||||
|
||||
#include "compiler/attr.h"
|
||||
|
||||
typedef struct {
|
||||
uint64_t r15;
|
||||
uint64_t r14;
|
||||
@ -33,7 +35,10 @@ typedef struct {
|
||||
uint64_t ss;
|
||||
} PACKED IntrStackFrame;
|
||||
|
||||
void intr_attchhandler(void (*fn)(void), int irq);
|
||||
void intr_attchhandler(void (*fn)(IntrStackFrame *frame), int irq);
|
||||
int32_t intr_dttchhandler(int irq);
|
||||
void intr_disable(void);
|
||||
void intr_enable(void);
|
||||
void intr_init(void);
|
||||
|
||||
#endif // HAL_INTR_H_
|
||||
#endif // INTR_INTR_H_
|
||||
@ -1,4 +1,4 @@
|
||||
#include "regs.S"
|
||||
#include "cpu/regs.S"
|
||||
|
||||
.extern intr_handleintr
|
||||
|
||||
@ -66,7 +66,9 @@
|
||||
_push_regs
|
||||
cld
|
||||
movq %rsp, %rdi
|
||||
sub $0x8, %rsp
|
||||
call intr_handleintr
|
||||
add $0x8, %rsp
|
||||
_pop_regs
|
||||
add $0x10, %rsp
|
||||
iretq
|
||||
68
kernel/intr/pic.c
Normal file
68
kernel/intr/pic.c
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "io/io.h"
|
||||
#include "intr/pic.h"
|
||||
#include "intr/intr.h"
|
||||
|
||||
#define PIC1_CMD 0x0020
|
||||
#define PIC1_DATA 0x0021
|
||||
#define PIC2_CMD 0x00A0
|
||||
#define PIC2_DATA 0x00A1
|
||||
|
||||
#define PIC_EOI 0x20
|
||||
|
||||
#define ICW1_ICW4 0x01
|
||||
#define ICW1_SINGLE 0x02
|
||||
#define ICW1_ADI 0x04
|
||||
#define ICW1_LTIM 0x08
|
||||
#define ICW1_INIT 0x10
|
||||
|
||||
#define ICW4_8086 0x01
|
||||
#define ICW4_AUTO 0x02
|
||||
#define ICW4_BUFSLAVE 0x04
|
||||
#define ICW4_BUFMASTER 0x0C
|
||||
#define ICW4_SFNM 0x10
|
||||
|
||||
void intr_pic_init(void) {
|
||||
io_out8(PIC1_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
io_out8(PIC2_CMD, ICW1_INIT | ICW1_ICW4);
|
||||
io_wait();
|
||||
|
||||
io_out8(PIC1_DATA, INTR_IRQBASE);
|
||||
io_wait();
|
||||
io_out8(PIC2_DATA, INTR_IRQBASE+8);
|
||||
io_wait();
|
||||
|
||||
io_out8(PIC1_DATA, 2);
|
||||
io_wait();
|
||||
io_out8(PIC2_DATA, 2);
|
||||
io_wait();
|
||||
|
||||
io_out8(PIC1_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
io_out8(PIC2_DATA, ICW4_8086);
|
||||
io_wait();
|
||||
|
||||
intr_pic_mask();
|
||||
}
|
||||
|
||||
void intr_pic_mask(void) {
|
||||
io_out8(PIC1_DATA, 0xFF);
|
||||
io_wait();
|
||||
io_out8(PIC2_DATA, 0xFF);
|
||||
io_wait();
|
||||
}
|
||||
|
||||
void intr_pic_unmask(void) {
|
||||
io_out8(PIC1_DATA, 0);
|
||||
io_wait();
|
||||
io_out8(PIC2_DATA, 0);
|
||||
io_wait();
|
||||
}
|
||||
|
||||
void intr_pic_eoi(bool pic2) {
|
||||
if (pic2)
|
||||
io_out8(PIC2_CMD, PIC_EOI);
|
||||
io_out8(PIC1_CMD, PIC_EOI);
|
||||
}
|
||||
11
kernel/intr/pic.h
Normal file
11
kernel/intr/pic.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef INTR_PIC_H_
|
||||
#define INTR_PIC_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void intr_pic_init(void);
|
||||
void intr_pic_eoi(bool pic2);
|
||||
void intr_pic_mask(void);
|
||||
void intr_pic_unmask(void);
|
||||
|
||||
#endif // INTR_PIC_H_
|
||||
@ -1,6 +1,7 @@
|
||||
#include <stdint.h>
|
||||
#include "pit.h"
|
||||
#include "io.h"
|
||||
#include "intr/pit.h"
|
||||
#include "io/io.h"
|
||||
#include "intr/intr.h"
|
||||
|
||||
#define PIT_COUNTER0 0x40
|
||||
#define PIT_CMD 0x43
|
||||
@ -25,15 +26,15 @@
|
||||
|
||||
volatile uint32_t PIT_TICKS;
|
||||
|
||||
void pit_init(void) {
|
||||
void intr_pit_wait(uint32_t ms) {
|
||||
uint32_t now = PIT_TICKS;
|
||||
while (PIT_TICKS - now < ms);
|
||||
}
|
||||
|
||||
void intr_pit_init(void) {
|
||||
uint32_t hz = 1000;
|
||||
uint32_t div = PIT_FREQ / hz;
|
||||
io_out8(PIT_CMD, PIT_CMD_BINARY | PIT_CMD_MODE3 | PIT_CMD_RW_BOTH | PIT_CMD_COUNTER0);
|
||||
io_out8(PIT_COUNTER0, div & 0xFF);
|
||||
io_out8(PIT_COUNTER0, div >> 8);
|
||||
}
|
||||
|
||||
void pit_wait(uint32_t ms) {
|
||||
uint32_t now = PIT_TICKS;
|
||||
while (PIT_TICKS - now < ms);
|
||||
}
|
||||
11
kernel/intr/pit.h
Normal file
11
kernel/intr/pit.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef INTR_PIT_H_
|
||||
#define INTR_PIT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern volatile uint32_t PIT_TICKS;
|
||||
|
||||
void intr_pit_init(void);
|
||||
void intr_pit_wait(uint32_t ms);
|
||||
|
||||
#endif // INTR_PIT_H_
|
||||
@ -1,4 +1,5 @@
|
||||
#include <stdint.h>
|
||||
#include "io/io.h"
|
||||
|
||||
uint8_t io_in8(uint16_t port) {
|
||||
uint8_t r;
|
||||
@ -44,3 +45,7 @@ void io_outs16(uint16_t port, const void *addr, int cnt) {
|
||||
: "memory", "cc"
|
||||
);
|
||||
}
|
||||
|
||||
void io_wait(void) {
|
||||
io_out8(0x80, 0);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef HAL_IO_H_
|
||||
#define HAL_IO_H_
|
||||
#ifndef IO_IO_H_
|
||||
#define IO_IO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -15,4 +15,6 @@ void io_out32(uint16_t port, uint32_t value);
|
||||
void io_ins16(uint16_t port, void *addr, int cnt);
|
||||
void io_outs16(uint16_t port, const void *addr, int cnt);
|
||||
|
||||
#endif // HAL_IO_H_
|
||||
void io_wait(void);
|
||||
|
||||
#endif // IO_IO_H_
|
||||
208
kernel/ipc/mbus/mbus.c
Normal file
208
kernel/ipc/mbus/mbus.c
Normal file
@ -0,0 +1,208 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "rbuf/rbuf.h"
|
||||
#include "proc/proc.h"
|
||||
#include "ipc/mbus/mbus.h"
|
||||
#include "std/string.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "util/util.h"
|
||||
#include "cjob/cjob.h"
|
||||
#include "hshtb.h"
|
||||
#include "errors.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
IpcMBuses IPC_MBUSES;
|
||||
|
||||
void ipc_mbus_gc_cjob(void *arg) {
|
||||
for (size_t i = 0; i < LEN(IPC_MBUSES.mbuses); i++) {
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
IpcMBus *mbus = &IPC_MBUSES.mbuses[i];
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
spinlock_acquire(&mbus->spinlock);
|
||||
if (mbus->_hshtbstate != HSHTB_TAKEN) {
|
||||
spinlock_release(&mbus->spinlock);
|
||||
continue;
|
||||
}
|
||||
|
||||
IpcMBusCons *cons, *constmp;
|
||||
LL_FOREACH_SAFE(mbus->consumers, cons, constmp) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc = NULL;
|
||||
LL_FINDPROP(PROCS.procs, proc, pid, cons->pid);
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
if (proc == NULL) {
|
||||
LL_REMOVE(mbus->consumers, cons);
|
||||
dlfree(cons->rbuf.buffer);
|
||||
dlfree(cons);
|
||||
}
|
||||
}
|
||||
spinlock_release(&mbus->spinlock);
|
||||
}
|
||||
}
|
||||
|
||||
void ipc_mbusinit(void) {
|
||||
memset(&IPC_MBUSES, 0, sizeof(IPC_MBUSES));
|
||||
spinlock_init(&IPC_MBUSES.spinlock);
|
||||
|
||||
cjob_register(&ipc_mbus_gc_cjob, NULL);
|
||||
}
|
||||
|
||||
IpcMBus *ipc_mbusmake(const char *name, size_t objsize, size_t objmax) {
|
||||
IpcMBus *mbus = NULL;
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_ALLOC(IPC_MBUSES.mbuses, ident, (char *)name, mbus);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
if (mbus == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbus->objsize = objsize;
|
||||
mbus->objmax = objmax;
|
||||
|
||||
return mbus;
|
||||
}
|
||||
|
||||
int32_t ipc_mbusdelete(const char *name) {
|
||||
IpcMBus *mbus = NULL;
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_GET(IPC_MBUSES.mbuses, ident, (char *)name, mbus);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
if (mbus == NULL) {
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
IpcMBusCons *cons, *constmp;
|
||||
spinlock_acquire(&mbus->spinlock);
|
||||
LL_FOREACH_SAFE(mbus->consumers, cons, constmp) {
|
||||
LL_REMOVE(mbus->consumers, cons);
|
||||
dlfree(cons->rbuf.buffer);
|
||||
dlfree(cons);
|
||||
}
|
||||
spinlock_release(&mbus->spinlock);
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_DELETE(IPC_MBUSES.mbuses, ident, (char *)name);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t ipc_mbuspublish(const char *name, const uint8_t *const buffer) {
|
||||
IpcMBus *mbus = NULL;
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_GET(IPC_MBUSES.mbuses, ident, (char *)name, mbus);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
if (mbus == NULL) {
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
IpcMBusCons *cons, *constmp;
|
||||
spinlock_acquire(&mbus->spinlock);
|
||||
LL_FOREACH_SAFE(mbus->consumers, cons, constmp) {
|
||||
for (size_t i = 0; i < mbus->objsize; i++) {
|
||||
if (rbuf_push(&cons->rbuf, buffer[i]) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
spinlock_release(&mbus->spinlock);
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t ipc_mbusconsume(const char *name, uint8_t *const buffer, uint64_t pid) {
|
||||
IpcMBus *mbus = NULL;
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_GET(IPC_MBUSES.mbuses, ident, (char *)name, mbus);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
if (mbus == NULL) {
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
IpcMBusCons *cons, *constmp;
|
||||
spinlock_acquire(&mbus->spinlock);
|
||||
LL_FOREACH_SAFE(mbus->consumers, cons, constmp) {
|
||||
if (cons->pid == pid) {
|
||||
for (; i < mbus->objsize; i++) {
|
||||
if (rbuf_pop(&cons->rbuf, &buffer[i]) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
spinlock_release(&mbus->spinlock);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int32_t ipc_mbusattch(const char *name, uint64_t pid) {
|
||||
IpcMBus *mbus = NULL;
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_GET(IPC_MBUSES.mbuses, ident, (char *)name, mbus);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
if (mbus == NULL) {
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
IpcMBusCons *cons = dlmalloc(sizeof(*cons));
|
||||
if (cons == NULL) {
|
||||
return E_NOMEMORY;
|
||||
}
|
||||
|
||||
memset(cons, 0, sizeof(*cons));
|
||||
cons->pid = pid;
|
||||
|
||||
uint8_t *buffer = dlmalloc(mbus->objsize * mbus->objmax);
|
||||
if (buffer == NULL) {
|
||||
dlfree(cons);
|
||||
return E_NOMEMORY;
|
||||
}
|
||||
rbuf_init(&cons->rbuf, buffer, mbus->objsize * mbus->objmax);
|
||||
|
||||
spinlock_acquire(&mbus->spinlock);
|
||||
LL_APPEND(mbus->consumers, cons);
|
||||
spinlock_release(&mbus->spinlock);
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t ipc_mbusdttch(const char *name, uint64_t pid) {
|
||||
IpcMBus *mbus = NULL;
|
||||
|
||||
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||
HSHTB_GET(IPC_MBUSES.mbuses, ident, (char *)name, mbus);
|
||||
spinlock_release(&IPC_MBUSES.spinlock);
|
||||
|
||||
if (mbus == NULL) {
|
||||
return E_NOENTRY;
|
||||
}
|
||||
|
||||
IpcMBusCons *cons, *constmp;
|
||||
spinlock_acquire(&mbus->spinlock);
|
||||
LL_FOREACH_SAFE(mbus->consumers, cons, constmp) {
|
||||
if (cons->pid == pid) {
|
||||
LL_REMOVE(mbus->consumers, cons);
|
||||
dlfree(cons->rbuf.buffer);
|
||||
dlfree(cons);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spinlock_release(&mbus->spinlock);
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
38
kernel/ipc/mbus/mbus.h
Normal file
38
kernel/ipc/mbus/mbus.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef IPC_MBUS_MBUS_H_
|
||||
#define IPC_MBUS_MBUS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "proc/proc.h"
|
||||
#include "rbuf/rbuf.h"
|
||||
|
||||
typedef struct IpcMBusCons {
|
||||
struct IpcMBusCons *next;
|
||||
uint64_t pid;
|
||||
RBuf rbuf;
|
||||
} IpcMBusCons;
|
||||
|
||||
typedef struct {
|
||||
int _hshtbstate;
|
||||
char ident[0x100];
|
||||
SpinLock spinlock;
|
||||
IpcMBusCons *consumers;
|
||||
size_t objsize, objmax;
|
||||
} IpcMBus;
|
||||
|
||||
typedef struct {
|
||||
SpinLock spinlock;
|
||||
IpcMBus mbuses[0x100];
|
||||
} IpcMBuses;
|
||||
|
||||
extern IpcMBuses IPC_MBUSES;
|
||||
|
||||
void ipc_mbusinit(void);
|
||||
IpcMBus *ipc_mbusmake(const char *name, size_t objsize, size_t objmax);
|
||||
int32_t ipc_mbusdelete(const char *name);
|
||||
int32_t ipc_mbuspublish(const char *name, const uint8_t *const buffer);
|
||||
int32_t ipc_mbusconsume(const char *name, uint8_t *const buffer, uint64_t pid);
|
||||
int32_t ipc_mbusattch(const char *name, uint64_t pid);
|
||||
int32_t ipc_mbusdttch(const char *name, uint64_t pid);
|
||||
|
||||
#endif // IPC_MBUS_MBUS_H_
|
||||
@ -2,14 +2,14 @@
|
||||
#include <stddef.h>
|
||||
#include "rbuf/rbuf.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "hal/hal.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "errors.h"
|
||||
#include "pipe.h"
|
||||
#include "ipc/pipe/pipe.h"
|
||||
#include "std/string.h"
|
||||
#include "kprintf.h"
|
||||
#include "errors.h"
|
||||
|
||||
int32_t ipc_pipeinit(IpcPipe *pipe, uint64_t pid) {
|
||||
hal_memset(pipe, 0, sizeof(*pipe));
|
||||
memset(pipe, 0, sizeof(*pipe));
|
||||
spinlock_init(&pipe->spinlock);
|
||||
pipe->ownerpid = pid;
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#include <limine.h>
|
||||
#include "kprintf.h"
|
||||
#include "banner.h"
|
||||
#include "hal/hal.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "pmm/pmm.h"
|
||||
#include "term/term.h"
|
||||
@ -15,6 +14,12 @@
|
||||
#include "randcrypto/randcrypto.h"
|
||||
#include "time/time.h"
|
||||
#include "diskpart/diskpart.h"
|
||||
#include "vmm/vmm.h"
|
||||
#include "cpu/hang.h"
|
||||
#include "cpu/gdt.h"
|
||||
#include "ipc/mbus/mbus.h"
|
||||
#include "pci/pci.h"
|
||||
#include "cjob/cjob.h"
|
||||
|
||||
void log_bootinfo(void) {
|
||||
char buf[100];
|
||||
@ -34,19 +39,23 @@ static volatile LIMINE_BASE_REVISION(2);
|
||||
|
||||
void kmain(void) {
|
||||
if (LIMINE_BASE_REVISION_SUPPORTED == false) {
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
|
||||
bootinfo_init();
|
||||
term_init(BOOT_INFO.fb->address);
|
||||
log_bootinfo();
|
||||
log_time();
|
||||
hal_init();
|
||||
gdt_init();
|
||||
pmm_init();
|
||||
hal_vmm_init();
|
||||
vmm_init();
|
||||
intr_init();
|
||||
randcrypto_init();
|
||||
cjob_init();
|
||||
ipc_mbusinit();
|
||||
dev_init();
|
||||
storedev_init();
|
||||
pci_init();
|
||||
diskpart_init();
|
||||
baseimg_init();
|
||||
vfs_init();
|
||||
|
||||
@ -18,18 +18,8 @@
|
||||
#define kvsnprintf vsnprintf_
|
||||
#define kvprintf vprintf_
|
||||
|
||||
#ifdef KPRINTF_COLORS
|
||||
# include "ansi_colors.h"
|
||||
# define LOG(component, fmt, ...) kprintf(CRESET "[" CYN component CRESET "]: " fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define LOG(component, fmt, ...) kprintf("["component"]: "fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef KPRINTF_COLORS
|
||||
# include "ansi_colors.h"
|
||||
# define ERR(component, fmt, ...) kprintf(CRESET "[" RED1 component CRESET "]: " fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
# define ERR(component, fmt, ...) kprintf("["component"]: "fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
#include "ansi_colors.h"
|
||||
#define LOG(component, fmt, ...) kprintf(CRESET "[" CYN component CRESET "]: " fmt, ##__VA_ARGS__)
|
||||
#define ERR(component, fmt, ...) kprintf(CRESET "[" RED1 component CRESET "]: " fmt, ##__VA_ARGS__)
|
||||
|
||||
#endif // KPRINTF_H_
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include "path.h"
|
||||
#include "hal/hal.h"
|
||||
#include "std/string.h"
|
||||
|
||||
void path_parse(const char *in, char *mp, char *path) {
|
||||
if (in == 0 || *in == 0) {
|
||||
@ -45,8 +45,8 @@ void path_parse(const char *in, char *mp, char *path) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hal_strstr(path, "/../") || hal_strstr(path, "/./")
|
||||
|| hal_strcmp(path, "..") == 0 || hal_strcmp(path, ".") == 0) {
|
||||
if (strstr(path, "/../") || strstr(path, "/./")
|
||||
|| strcmp(path, "..") == 0 || strcmp(path, ".") == 0) {
|
||||
mp[0] = 0;
|
||||
path[0] = 0;
|
||||
return;
|
||||
|
||||
54
kernel/pci/ata/ata.c
Normal file
54
kernel/pci/ata/ata.c
Normal file
@ -0,0 +1,54 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "pci/pci.h"
|
||||
#include "storedev/storedev.h"
|
||||
#include "storedev/atasd.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
#define ATA_PROBE(STRING, IOBASE, CTRLBASE, S_OR_M) \
|
||||
ps = ata_probesize_bytes((IOBASE), (CTRLBASE), (S_OR_M)); \
|
||||
if (ps > 0) { \
|
||||
AtaSdInitExtra extra = { \
|
||||
.devno = (S_OR_M), \
|
||||
.capacity = ps, \
|
||||
.iobase = (IOBASE), \
|
||||
.ctrlbase = (CTRLBASE), \
|
||||
}; \
|
||||
storedev_create(STOREDEV_ATASD, (STRING), (void *)&extra); \
|
||||
}
|
||||
|
||||
#define ATA_MASTER 0x00
|
||||
#define ATA_SLAVE 0x01
|
||||
|
||||
#define ATA_PRIM_IO 0x1F0
|
||||
#define ATA_PRIM_CTRL 0x3F6
|
||||
#define ATA_SCND_IO 0x170
|
||||
#define ATA_SCND_CTRL 0x376
|
||||
|
||||
void pci_ata_init(void) {
|
||||
PciDev dev = pci_getdev(0x8086, 0x7010, -1);
|
||||
|
||||
uint16_t iobase, ctrlbase;
|
||||
uint64_t ps;
|
||||
|
||||
uint32_t bar0 = pci_read(dev, PCI_BAR0);
|
||||
uint32_t bar1 = pci_read(dev, PCI_BAR1);
|
||||
uint32_t bar2 = pci_read(dev, PCI_BAR2);
|
||||
uint32_t bar3 = pci_read(dev, PCI_BAR3);
|
||||
|
||||
LOG("pci", "ATA bar0=0x%x, bar1=0x%x, bar2=0x%x, bar3=0x%x\n", bar0, bar1, bar2, bar3);
|
||||
|
||||
iobase = (bar0 & 0xFFFFFFFC) + ATA_PRIM_IO * (!bar0);
|
||||
ctrlbase = (bar1 & 0xFFFFFFFC) + ATA_PRIM_CTRL * (!bar1);
|
||||
LOG("pci", "ATA CHANNEL PRIM: iobase=0x%x, ctrlbase=0x%x\n", iobase, ctrlbase);
|
||||
if (!bar0 || !bar1) LOG("pci", "falling back to ISA\n");
|
||||
ATA_PROBE("atasd0m", iobase, ctrlbase, ATA_MASTER);
|
||||
ATA_PROBE("atasd0s", iobase, ctrlbase, ATA_SLAVE);
|
||||
|
||||
iobase = (bar2 & 0xFFFFFFFC) + ATA_SCND_IO * (!bar2);
|
||||
ctrlbase = (bar3 & 0xFFFFFFFC) + ATA_SCND_CTRL * (!bar3);
|
||||
LOG("pci", "ATA CHANNEL SCND: iobase=0x%x, ctrlbase=0x%x\n", iobase, ctrlbase);
|
||||
if (!bar2 || !bar3) LOG("pci", "falling back to ISA\n");
|
||||
ATA_PROBE("atasd1m", iobase, ctrlbase, ATA_MASTER);
|
||||
ATA_PROBE("atasd2s", iobase, ctrlbase, ATA_SLAVE);
|
||||
}
|
||||
6
kernel/pci/ata/ata.h
Normal file
6
kernel/pci/ata/ata.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef PCI_ATA_ATA_H_
|
||||
#define PCI_ATA_ATA_H_
|
||||
|
||||
void pci_ata_init(void);
|
||||
|
||||
#endif // PCI_ATA__ATA_H_
|
||||
185
kernel/pci/pci.c
Normal file
185
kernel/pci/pci.c
Normal file
@ -0,0 +1,185 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "pci/pci.h"
|
||||
#include "pci/ata/ata.h"
|
||||
#include "pci/qemu_pci_serial/qemu_pci_serial.h"
|
||||
#include "io/io.h"
|
||||
#include "std/string.h"
|
||||
#include "util/util.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
static PciDev PCI_DEV_ZERO = {0};
|
||||
uint32_t PCI_SIZE_MAP[100] = {0};
|
||||
|
||||
uint32_t pci_read(PciDev dev, uint32_t field) {
|
||||
dev.fieldnum = (field & 0xFC) >> 2;
|
||||
dev.enable = 1;
|
||||
io_out32(PCI_CFG_ADDR, dev.bits);
|
||||
|
||||
uint32_t size = PCI_SIZE_MAP[field];
|
||||
uint8_t u8; uint16_t u16; uint32_t u32;
|
||||
switch (size) {
|
||||
case 1:
|
||||
u8 = io_in8(PCI_CFG_DATA + (field & 0x3));
|
||||
return (uint32_t)u8;
|
||||
case 2:
|
||||
u16 = io_in16(PCI_CFG_DATA + (field & 0x2));
|
||||
return (uint32_t)u16;
|
||||
case 4:
|
||||
u32 = io_in32(PCI_CFG_DATA);
|
||||
return u32;
|
||||
default:
|
||||
return 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void pci_write(PciDev dev, uint32_t field, uint32_t v) {
|
||||
dev.fieldnum = (field & 0xFC) >> 2;
|
||||
dev.enable = 1;
|
||||
io_out32(PCI_CFG_ADDR, dev.bits);
|
||||
io_out32(PCI_CFG_DATA, v);
|
||||
}
|
||||
|
||||
uint32_t pci_devtype(PciDev dev) {
|
||||
uint32_t a = pci_read(dev, PCI_CLASS) << 8;
|
||||
uint32_t b = pci_read(dev, PCI_SUBCLASS);
|
||||
return a | b;
|
||||
}
|
||||
|
||||
uint32_t pci_scndrybus(PciDev dev) {
|
||||
return pci_read(dev, PCI_SCNDRY_BUS);
|
||||
}
|
||||
|
||||
uint32_t pci_isend(PciDev dev) {
|
||||
return !(pci_read(dev, PCI_HDRTYPE));
|
||||
}
|
||||
|
||||
PciDev pci_scanfn(uint16_t vendorid, uint16_t deviceid, uint32_t bus,
|
||||
uint32_t device, uint32_t fn, int devtype) {
|
||||
PciDev dev; memset(&dev, 0, sizeof(dev));
|
||||
dev.busnum = bus;
|
||||
dev.devnum = device;
|
||||
dev.fnnum = fn;
|
||||
|
||||
// bridge
|
||||
if (pci_devtype(dev) == 0x0604) {
|
||||
pci_scanbus(vendorid, deviceid, pci_scndrybus(dev), devtype);
|
||||
}
|
||||
if (devtype == -1 || (uint32_t)devtype == pci_devtype(dev)) {
|
||||
uint32_t venid = pci_read(dev, PCI_VENDORID);
|
||||
uint32_t devid = pci_read(dev, PCI_DEVICEID);
|
||||
|
||||
if (devid == deviceid && venid == vendorid) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
PciDev pci_scanbus(uint16_t vendorid, uint16_t deviceid,
|
||||
uint32_t bus, int devtype) {
|
||||
for (uint32_t device = 0; device < PCI_DEV_PER_BUS; device++) {
|
||||
PciDev d = pci_scandev(vendorid, deviceid, bus, device, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
PciDev pci_scandev(uint16_t vendorid, uint16_t deviceid,
|
||||
uint32_t bus, uint32_t device, int devtype) {
|
||||
PciDev dev; memset(&dev, 0, sizeof(dev));
|
||||
dev.busnum = bus;
|
||||
dev.devnum = device;
|
||||
|
||||
if (pci_read(dev, PCI_VENDORID) == 0xFFFF) {
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
PciDev d = pci_scanfn(vendorid, deviceid, bus, device, 0, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
|
||||
if (pci_isend(dev)) {
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
for (uint32_t fn = 1; fn < PCI_FN_PER_DEV; fn++) {
|
||||
if (pci_read(dev, PCI_VENDORID) != 0xFFFF) {
|
||||
d = pci_scanfn(vendorid, deviceid, bus, device, fn, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
PciDev pci_getdev(uint16_t vendorid, uint16_t deviceid, int devtype) {
|
||||
PciDev d = pci_scanbus(vendorid, deviceid, 0, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
|
||||
if (pci_isend(PCI_DEV_ZERO)) {
|
||||
ERR("pci", "pci_getdev() failed for 0x%04x/0x%04x,%d\n", vendorid, deviceid, devtype);
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
for (uint32_t fn = 1; fn < PCI_FN_PER_DEV; fn++) {
|
||||
PciDev d2; memset(&d2, 0, sizeof(d2));
|
||||
d2.fnnum = fn;
|
||||
|
||||
if (pci_read(d2, PCI_VENDORID) == 0xFFFF) {
|
||||
break;
|
||||
}
|
||||
|
||||
d = pci_scanbus(vendorid, deviceid, fn, devtype);
|
||||
if (d.bits) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return PCI_DEV_ZERO;
|
||||
}
|
||||
|
||||
void pci_init_size_map(void) {
|
||||
PCI_SIZE_MAP[PCI_VENDORID] = 2;
|
||||
PCI_SIZE_MAP[PCI_DEVICEID] = 2;
|
||||
PCI_SIZE_MAP[PCI_CMD] = 2;
|
||||
PCI_SIZE_MAP[PCI_STATUS] = 2;
|
||||
PCI_SIZE_MAP[PCI_SUBCLASS] = 1;
|
||||
PCI_SIZE_MAP[PCI_CLASS] = 1;
|
||||
PCI_SIZE_MAP[PCI_CACHELINESZ] = 1;
|
||||
PCI_SIZE_MAP[PCI_LTNCY_TIMER] = 1;
|
||||
PCI_SIZE_MAP[PCI_HDRTYPE] = 1;
|
||||
PCI_SIZE_MAP[PCI_BIST] = 1;
|
||||
PCI_SIZE_MAP[PCI_BAR0] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR1] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR2] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR3] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR4] = 4;
|
||||
PCI_SIZE_MAP[PCI_BAR5] = 4;
|
||||
PCI_SIZE_MAP[PCI_INTRLINE] = 1;
|
||||
PCI_SIZE_MAP[PCI_SCNDRY_BUS] = 1;
|
||||
}
|
||||
|
||||
|
||||
PciInitFn PCI_INIT_ARRAY[PCI_INIT_ARRAY_MAX] = {
|
||||
&pci_ata_init,
|
||||
&pci_qemu_pci_serial_init,
|
||||
};
|
||||
|
||||
void pci_init_devs(void) {
|
||||
for (size_t i = 0; i < LEN(PCI_INIT_ARRAY); i++) {
|
||||
if (PCI_INIT_ARRAY[i] != NULL)
|
||||
PCI_INIT_ARRAY[i]();
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init(void) {
|
||||
pci_init_size_map();
|
||||
pci_init_devs();
|
||||
}
|
||||
71
kernel/pci/pci.h
Normal file
71
kernel/pci/pci.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef PCI_PCI_H_
|
||||
#define PCI_PCI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef union {
|
||||
uint32_t bits;
|
||||
struct {
|
||||
uint32_t alwayszero: 2;
|
||||
uint32_t fieldnum: 6;
|
||||
uint32_t fnnum: 3;
|
||||
uint32_t devnum: 5;
|
||||
uint32_t busnum: 8;
|
||||
uint32_t resv: 7;
|
||||
uint32_t enable: 1;
|
||||
};
|
||||
} PciDev;
|
||||
|
||||
#define PCI_CFG_ADDR 0xCF8
|
||||
#define PCI_CFG_DATA 0xCFC
|
||||
|
||||
#define PCI_VENDORID 0x00
|
||||
#define PCI_DEVICEID 0x02
|
||||
#define PCI_CMD 0x04
|
||||
#define PCI_STATUS 0x06
|
||||
#define PCI_REVID 0x08
|
||||
#define PCI_PROGIF 0x09
|
||||
#define PCI_SUBCLASS 0x0A
|
||||
#define PCI_CLASS 0x0B
|
||||
#define PCI_CACHELINESZ 0x0C
|
||||
#define PCI_LTNCY_TIMER 0x0D
|
||||
#define PCI_HDRTYPE 0x0E
|
||||
#define PCI_BIST 0x0F
|
||||
#define PCI_BAR0 0x10
|
||||
#define PCI_BAR1 0x14
|
||||
#define PCI_BAR2 0x18
|
||||
#define PCI_BAR3 0x1C
|
||||
#define PCI_BAR4 0x20
|
||||
#define PCI_BAR5 0x24
|
||||
#define PCI_INTRLINE 0x3C
|
||||
#define PCI_SCNDRY_BUS 0x09
|
||||
|
||||
#define PCI_HDR_DEV 0
|
||||
#define PCI_HDR_BRIDGE 1
|
||||
#define PCI_HDR_CARDBUS 2
|
||||
|
||||
#define PCI_DEV_PER_BUS 32
|
||||
#define PCI_FN_PER_DEV 32
|
||||
|
||||
uint32_t pci_read(PciDev dev, uint32_t field);
|
||||
void pci_write(PciDev dev, uint32_t field, uint32_t v);
|
||||
uint32_t pci_devtype(PciDev dev);
|
||||
uint32_t pci_scndrybus(PciDev dev);
|
||||
uint32_t pci_isend(PciDev dev);
|
||||
PciDev pci_scanfn(uint16_t vendorid, uint16_t deviceid, uint32_t bus,
|
||||
uint32_t device, uint32_t fn, int devtype);
|
||||
PciDev pci_scanbus(uint16_t vendorid, uint16_t deviceid,
|
||||
uint32_t bus, int devtype);
|
||||
PciDev pci_scandev(uint16_t vendorid, uint16_t deviceid,
|
||||
uint32_t bus, uint32_t device, int devtype);
|
||||
PciDev pci_getdev(uint16_t vendorid, uint16_t deviceid, int devtype);
|
||||
|
||||
void pci_init(void);
|
||||
|
||||
#define PCI_INIT_ARRAY_MAX 0x100
|
||||
|
||||
typedef void (*PciInitFn)(void);
|
||||
extern PciInitFn PCI_INIT_ARRAY[PCI_INIT_ARRAY_MAX];
|
||||
|
||||
#endif // PCI_PCI_H_
|
||||
187
kernel/pci/qemu_pci_serial/qemu_pci_serial.c
Normal file
187
kernel/pci/qemu_pci_serial/qemu_pci_serial.c
Normal file
@ -0,0 +1,187 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "pci/pci.h"
|
||||
#include "pci/qemu_pci_serial/qemu_pci_serial.h"
|
||||
#include "io/io.h"
|
||||
#include "sysdefs/dev.h"
|
||||
#include "util/util.h"
|
||||
#include "dev/dev.h"
|
||||
#include "cjob/cjob.h"
|
||||
#include "proc/proc.h"
|
||||
#include "errors.h"
|
||||
#include "hshtb.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
static QemuPciSerialDev QEMU_PCI_SERIAL_DEV;
|
||||
|
||||
// https://wiki.osdev.org/Serial_Ports
|
||||
|
||||
void _serial_init(uint16_t iobase) {
|
||||
io_out8(iobase+1, 0x00);
|
||||
io_out8(iobase+3, 0x80);
|
||||
io_out8(iobase+0, 0x03);
|
||||
io_out8(iobase+1, 0x00);
|
||||
io_out8(iobase+3, 0x03);
|
||||
io_out8(iobase+2, 0xC7);
|
||||
io_out8(iobase+4, 0x0B);
|
||||
io_out8(iobase+4, 0x1E);
|
||||
io_out8(iobase+0, 0xAE);
|
||||
|
||||
if (io_in8(iobase+0) != 0xAE) {
|
||||
ERR("pci", "QEMU_PCI_SERIAL serial is faulty!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
io_out8(iobase+4, 0x0F);
|
||||
}
|
||||
|
||||
int _serial_recvready(uint16_t iobase) {
|
||||
return io_in8(iobase+5) & 1;
|
||||
}
|
||||
|
||||
uint8_t _serial_recvb(uint16_t iobase) {
|
||||
return io_in8(iobase);
|
||||
}
|
||||
|
||||
int _serial_sendready(uint16_t iobase) {
|
||||
return io_in8(iobase+5) & 0x20;
|
||||
}
|
||||
|
||||
void _serial_sendb(uint16_t iobase, uint8_t b) {
|
||||
io_out8(iobase, b);
|
||||
}
|
||||
|
||||
int32_t qemu_pci_serial_dev_sendb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)len; (void)pid;
|
||||
|
||||
QemuPciSerialDev *qpsd = dev->extra;
|
||||
|
||||
if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) {
|
||||
return E_DEVLOCKED;
|
||||
}
|
||||
|
||||
_serial_sendb(qpsd->iobase, buffer[0]);
|
||||
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
int32_t qemu_pci_serial_dev_sendready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)buffer; (void)len; (void)pid;
|
||||
|
||||
QemuPciSerialDev *qpsd = dev->extra;
|
||||
|
||||
if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) {
|
||||
return E_DEVLOCKED;
|
||||
}
|
||||
|
||||
return _serial_sendready(qpsd->iobase);
|
||||
}
|
||||
|
||||
int32_t qemu_pci_serial_dev_recvb(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)buffer; (void)len; (void)pid;
|
||||
|
||||
QemuPciSerialDev *qpsd = dev->extra;
|
||||
|
||||
if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) {
|
||||
return E_DEVLOCKED;
|
||||
}
|
||||
|
||||
return _serial_recvb(qpsd->iobase);
|
||||
}
|
||||
|
||||
int32_t qemu_pci_serial_dev_recvready(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)buffer; (void)len; (void)pid;
|
||||
|
||||
QemuPciSerialDev *qpsd = dev->extra;
|
||||
|
||||
if (qpsd->lockstate != -1 && qpsd->lockstate != (int)pid) {
|
||||
return E_DEVLOCKED;
|
||||
}
|
||||
|
||||
return _serial_recvready(qpsd->iobase);
|
||||
}
|
||||
|
||||
int32_t qemu_pci_serial_dev_lock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)buffer; (void)len; (void)pid;
|
||||
|
||||
QemuPciSerialDev *qpsd = dev->extra;
|
||||
|
||||
if (qpsd->lockstate == (int)pid) {
|
||||
return E_OK;
|
||||
}
|
||||
|
||||
if (qpsd->lockstate == -1) {
|
||||
qpsd->lockstate = (int)pid;
|
||||
return E_OK;
|
||||
}
|
||||
return E_DEVLOCKED;
|
||||
}
|
||||
|
||||
int32_t qemu_pci_serial_dev_unlock(struct Dev *dev, uint8_t *buffer, size_t len, uint64_t pid) {
|
||||
(void)buffer; (void)len; (void)pid;
|
||||
|
||||
QemuPciSerialDev *qpsd = dev->extra;
|
||||
|
||||
if (qpsd->lockstate == (int)pid) {
|
||||
qpsd->lockstate = -1;
|
||||
return E_OK;
|
||||
}
|
||||
return E_DEVNOTYOURLOCK;
|
||||
}
|
||||
|
||||
void pci_qemu_pci_serial_gc_cjob(void *arg) {
|
||||
Dev *dev = arg;
|
||||
|
||||
QemuPciSerialDev *qpsd;
|
||||
|
||||
spinlock_acquire(&dev->spinlock);
|
||||
qpsd = dev->extra;
|
||||
uint64_t pid = qpsd->lockstate;
|
||||
spinlock_release(&dev->spinlock);
|
||||
|
||||
Proc *proc = NULL;
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
LL_FINDPROP(PROCS.procs, proc, pid, pid);
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
|
||||
if (proc == NULL) {
|
||||
spinlock_acquire(&dev->spinlock);
|
||||
qpsd = dev->extra;
|
||||
qpsd->lockstate = -1;
|
||||
spinlock_release(&dev->spinlock);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_qemu_pci_serial_init(void) {
|
||||
PciDev dev = pci_getdev(0x1B36, 0x0002, -1);
|
||||
if (!dev.bits) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bar0 = pci_read(dev, PCI_BAR0);
|
||||
|
||||
LOG("pci", "QEMU_PCI_SERIAL bar0=0x%x\n", bar0);
|
||||
|
||||
uint16_t iobase = bar0 & 0xFFFFFFFC;
|
||||
LOG("pci", "QEMU_PCI_SERIAL iobase=0x%x\n", iobase);
|
||||
|
||||
QEMU_PCI_SERIAL_DEV._magic = QEMU_PCI_SERIAL_MAGIC;
|
||||
QEMU_PCI_SERIAL_DEV.iobase = iobase;
|
||||
QEMU_PCI_SERIAL_DEV.lockstate = -1;
|
||||
|
||||
Dev *serialdev = NULL;
|
||||
HSHTB_ALLOC(DEVTABLE.devs, ident, "serialdev", serialdev);
|
||||
serialdev->fns[0] = &qemu_pci_serial_dev_sendb;
|
||||
serialdev->fns[1] = &qemu_pci_serial_dev_sendready;
|
||||
serialdev->fns[2] = &qemu_pci_serial_dev_recvb;
|
||||
serialdev->fns[3] = &qemu_pci_serial_dev_recvready;
|
||||
serialdev->fns[4] = &qemu_pci_serial_dev_lock;
|
||||
serialdev->fns[5] = &qemu_pci_serial_dev_unlock;
|
||||
spinlock_init(&serialdev->spinlock);
|
||||
serialdev->extra = &QEMU_PCI_SERIAL_DEV;
|
||||
|
||||
cjob_register(&pci_qemu_pci_serial_gc_cjob, serialdev);
|
||||
|
||||
_serial_init(QEMU_PCI_SERIAL_DEV.iobase);
|
||||
}
|
||||
|
||||
17
kernel/pci/qemu_pci_serial/qemu_pci_serial.h
Normal file
17
kernel/pci/qemu_pci_serial/qemu_pci_serial.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef PCI_QEMU_PCI_SERIAL_QEMU_PCI_SERIAL_H_
|
||||
#define PCI_QEMU_PCI_SERIAL_QEMU_PCI_SERIAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define QEMU_PCI_SERIAL_MAGIC 0x1234
|
||||
|
||||
typedef struct {
|
||||
uint32_t _magic;
|
||||
uint16_t iobase;
|
||||
int lockstate;
|
||||
} QemuPciSerialDev;
|
||||
|
||||
void pci_qemu_pci_serial_init(void);
|
||||
|
||||
#endif // PCI_QEMU_PCI_SERIAL_QEMU_PCI_SERIAL_H_
|
||||
@ -1,12 +1,13 @@
|
||||
#include <stddef.h>
|
||||
#include <limine.h>
|
||||
#include "pmm.h"
|
||||
#include "kprintf.h"
|
||||
#include "pmm/pmm.h"
|
||||
#include "bitmap/bitmap.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "util/util.h"
|
||||
#include "hal/hal.h"
|
||||
#include "std/string.h"
|
||||
#include "cpu/hang.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
PhysMem PHYS_MEM;
|
||||
|
||||
@ -31,13 +32,13 @@ void pmm_init(void) {
|
||||
|
||||
if (!memmap_ent) {
|
||||
ERR("pmm", "required memory: {%lx}\n", bm->nbytes);
|
||||
hal_hang();
|
||||
cpu_hang();
|
||||
}
|
||||
|
||||
size_t physbegin = memmap_ent->base;
|
||||
bm->map = (uint8_t *)(physbegin + BOOT_INFO.hhdm_off);
|
||||
|
||||
hal_memset(bm->map, 0xff, bm->nbytes);
|
||||
memset(bm->map, 0xff, bm->nbytes);
|
||||
for (size_t i = 0; i < BOOT_INFO.memmap_entrycount; i++) {
|
||||
struct limine_memmap_entry *entry = BOOT_INFO.memmap_entries[i];
|
||||
if (entry == memmap_ent) {
|
||||
|
||||
@ -1,26 +1,30 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "hal/hal.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "proc.h"
|
||||
#include "proc/proc.h"
|
||||
#include "dlmalloc/malloc.h"
|
||||
#include "pmm/pmm.h"
|
||||
#include "util/util.h"
|
||||
#include "kprintf.h"
|
||||
#include "elf.h"
|
||||
#include "errors.h"
|
||||
#include "vfs/vfs.h"
|
||||
#include "bootinfo/bootinfo.h"
|
||||
#include "ipc/pipe/pipe.h"
|
||||
#include "ipc/mbus/mbus.h"
|
||||
#include "sysdefs/proc.h"
|
||||
#include "sysdefs/fs.h"
|
||||
#include "time/time.h"
|
||||
|
||||
#define PROC_REAPER_FREQ 30
|
||||
#include "std/string.h"
|
||||
#include "cpu/gdt.h"
|
||||
#include "intr/intr.h"
|
||||
#include "intr/pic.h"
|
||||
#include "vmm/vmm.h"
|
||||
#include "proc/switch.h"
|
||||
#include "cjob/cjob.h"
|
||||
#include "elf.h"
|
||||
#include "errors.h"
|
||||
#include "kprintf.h"
|
||||
|
||||
uint64_t pids = 0;
|
||||
uint64_t sched_ticks = 0;
|
||||
|
||||
Procs PROCS;
|
||||
|
||||
@ -47,25 +51,25 @@ ElfAuxval proc_load_elf_segs(Proc *proc, uint8_t *data) {
|
||||
aux.phdr = (uint64_t)phdr->p_vaddr;
|
||||
} break;
|
||||
case PT_LOAD: {
|
||||
uint64_t off = phdr->p_vaddr & (HAL_PAGE_SIZE - 1);
|
||||
uint64_t blocks = (off + phdr->p_memsz + HAL_PAGE_SIZE - 1) / HAL_PAGE_SIZE;
|
||||
uint64_t off = phdr->p_vaddr & (VMM_PAGE_SIZE - 1);
|
||||
uint64_t blocks = (off + phdr->p_memsz + VMM_PAGE_SIZE - 1) / VMM_PAGE_SIZE;
|
||||
|
||||
uint8_t *physaddr = pmm_alloc(blocks);
|
||||
uint8_t *virtaddr = (uint8_t *)(phdr->p_vaddr & ~(HAL_PAGE_SIZE - 1));
|
||||
uint8_t *virtaddr = (uint8_t *)(phdr->p_vaddr & ~(VMM_PAGE_SIZE - 1));
|
||||
|
||||
hal_memset(VIRT(physaddr), 0, blocks * HAL_PAGE_SIZE);
|
||||
hal_memcpy(VIRT(physaddr) + off, (data + phdr->p_offset), phdr->p_filesz);
|
||||
memset(VIRT(physaddr), 0, blocks * VMM_PAGE_SIZE);
|
||||
memcpy(VIRT(physaddr) + off, (data + phdr->p_offset), phdr->p_filesz);
|
||||
|
||||
uint32_t pgflags = HAL_PG_USER | HAL_PG_PRESENT;
|
||||
uint32_t pgflags = VMM_PG_USER | VMM_PG_PRESENT;
|
||||
if (phdr->p_flags & PF_W) {
|
||||
pgflags |= HAL_PG_RW;
|
||||
pgflags |= VMM_PG_RW;
|
||||
}
|
||||
hal_vmm_map_range(proc->platformdata.cr3, virtaddr, physaddr, blocks * HAL_PAGE_SIZE, pgflags);
|
||||
vmm_map_range(proc->platformdata.cr3, virtaddr, physaddr, blocks * VMM_PAGE_SIZE, pgflags);
|
||||
|
||||
VasRange *range = dlmalloc(sizeof(*range));
|
||||
range->virtstart = virtaddr;
|
||||
range->physstart = physaddr;
|
||||
range->size = blocks * HAL_PAGE_SIZE;
|
||||
range->size = blocks * VMM_PAGE_SIZE;
|
||||
range->pgflags = pgflags;
|
||||
|
||||
LL_APPEND(proc->vas, range);
|
||||
@ -105,11 +109,11 @@ Proc *proc_spawnuser(char *mountpoint, char *path) {
|
||||
vfs_close(vobj);
|
||||
|
||||
Proc *proc = dlmalloc(sizeof(*proc));
|
||||
hal_memset(proc, 0, sizeof(*proc));
|
||||
memset(proc, 0, sizeof(*proc));
|
||||
ksprintf(proc->name, "%s:%s", mountpoint, path);
|
||||
|
||||
hal_memset(&proc->platformdata.trapframe, 0, sizeof(proc->platformdata.trapframe));
|
||||
proc->platformdata.cr3 = hal_vmm_userproc_pml4_phys();
|
||||
memset(&proc->platformdata.trapframe, 0, sizeof(proc->platformdata.trapframe));
|
||||
proc->platformdata.cr3 = vmm_userproc_pml4_phys();
|
||||
|
||||
uint8_t *kstackp = (uint8_t *)pmm_alloc(PROC_STACKBLOCKS) + PROC_STACKSIZE;
|
||||
proc->platformdata.kstack = kstackp;
|
||||
@ -119,8 +123,8 @@ Proc *proc_spawnuser(char *mountpoint, char *path) {
|
||||
uint64_t virttop = PROC_USER_STACK_TOP;
|
||||
uint64_t virtbase = virttop - PROC_STACKSIZE;
|
||||
|
||||
uint32_t flags = HAL_PG_RW | HAL_PG_PRESENT | HAL_PG_USER;
|
||||
hal_vmm_map_range(proc->platformdata.cr3, (void *)virtbase, (void *)pstackp, PROC_STACKSIZE, flags);
|
||||
uint32_t flags = VMM_PG_RW | VMM_PG_PRESENT | VMM_PG_USER;
|
||||
vmm_map_range(proc->platformdata.cr3, (void *)virtbase, (void *)pstackp, PROC_STACKSIZE, flags);
|
||||
|
||||
VasRange *range = dlmalloc(sizeof(*range));
|
||||
range->virtstart = (uint8_t *)virtbase;
|
||||
@ -171,7 +175,33 @@ Proc *proc_nextready(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void proc_reaper(void) {
|
||||
void proc_sched(void *cpustate) {
|
||||
intr_disable();
|
||||
|
||||
memcpy(&PROCS.current->platformdata.trapframe, cpustate, sizeof(IntrStackFrame));
|
||||
|
||||
PROCS.current = proc_nextready();
|
||||
|
||||
cjob_runjobs();
|
||||
|
||||
tss.rsp0 = (uint64_t)VIRT(PROCS.current->platformdata.kstack);
|
||||
proc_switch(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
|
||||
}
|
||||
|
||||
void proc_kill(Proc *proc) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
proc->state = PROC_ZOMBIE;
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
}
|
||||
|
||||
void proc_killself(void) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc = PROCS.current;
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
proc_kill(proc);
|
||||
}
|
||||
|
||||
void proc_gc_cjob(void *arg) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *head, *tmp;
|
||||
LL_FOREACH_SAFE(PROCS.procs, head, tmp) {
|
||||
@ -202,8 +232,8 @@ void proc_reaper(void) {
|
||||
|
||||
VasRange *vas, *vastmp;
|
||||
LL_FOREACH_SAFE(zombie->vas, vas, vastmp) {
|
||||
hal_vmm_unmap_range(zombie->platformdata.cr3, vas->virtstart, vas->physstart, vas->size);
|
||||
pmm_free((uintptr_t)vas->physstart, vas->size / HAL_PAGE_SIZE);
|
||||
vmm_unmap_range(zombie->platformdata.cr3, vas->virtstart, vas->physstart, vas->size);
|
||||
pmm_free((uintptr_t)vas->physstart, vas->size / VMM_PAGE_SIZE);
|
||||
dlfree(vas);
|
||||
}
|
||||
|
||||
@ -219,44 +249,19 @@ void proc_reaper(void) {
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
}
|
||||
|
||||
void proc_sched(void *cpustate) {
|
||||
hal_intr_disable();
|
||||
sched_ticks++;
|
||||
|
||||
hal_memcpy(&PROCS.current->platformdata.trapframe, cpustate, sizeof(IntrStackFrame));
|
||||
|
||||
PROCS.current = proc_nextready();
|
||||
|
||||
if (sched_ticks % PROC_REAPER_FREQ == 0) {
|
||||
proc_reaper();
|
||||
}
|
||||
|
||||
tss.rsp0 = (uint64_t)VIRT(PROCS.current->platformdata.kstack);
|
||||
hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
|
||||
}
|
||||
|
||||
void proc_kill(Proc *proc) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
proc->state = PROC_ZOMBIE;
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
}
|
||||
|
||||
void proc_killself(void) {
|
||||
spinlock_acquire(&PROCS.spinlock);
|
||||
Proc *proc = PROCS.current;
|
||||
proc_kill(proc);
|
||||
spinlock_release(&PROCS.spinlock);
|
||||
}
|
||||
|
||||
void proc_init(void) {
|
||||
spinlock_init(&PROCS.spinlock);
|
||||
PROCS.procs = NULL;
|
||||
|
||||
cjob_register(&proc_gc_cjob, NULL);
|
||||
|
||||
Proc *init = proc_spawnuser("base", "/bin/init");
|
||||
PROCS.current = init;
|
||||
proc_register(init);
|
||||
init->state = PROC_READY;
|
||||
|
||||
intr_pic_unmask();
|
||||
|
||||
tss.rsp0 = (uint64_t)VIRT(PROCS.current->platformdata.kstack);
|
||||
hal_switchproc(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
|
||||
proc_switch(&PROCS.current->platformdata.trapframe, (void *)PROCS.current->platformdata.cr3);
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
#define PROC_PROC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hal/hal.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "bitmap/bitmap.h"
|
||||
#include "vfs/vfs.h"
|
||||
@ -10,6 +9,9 @@
|
||||
#include "sysdefs/proc.h"
|
||||
#include "sysdefs/time.h"
|
||||
#include "dev/dev.h"
|
||||
#include "std/string.h"
|
||||
#include "intr/intr.h"
|
||||
#include "vmm/vmm.h"
|
||||
|
||||
#define PROC_NAME_MAX 0x100
|
||||
|
||||
@ -90,7 +92,7 @@ void proc_kill(Proc *proc);
|
||||
#define PROC_ARG(proc, str) \
|
||||
do { \
|
||||
ProcArg *__arg = dlmalloc(sizeof(*__arg)); \
|
||||
hal_strcpy(__arg->string, (str)); \
|
||||
strcpy(__arg->string, (str)); \
|
||||
LL_APPEND((proc)->procargs.list, __arg); \
|
||||
(proc)->procargs.len++; \
|
||||
} while(0)
|
||||
|
||||
9
kernel/proc/switch.S
Normal file
9
kernel/proc/switch.S
Normal file
@ -0,0 +1,9 @@
|
||||
#include "cpu/regs.S"
|
||||
|
||||
.global proc_switch
|
||||
proc_switch:
|
||||
movq %rsi, %cr3
|
||||
mov %rdi, %rsp
|
||||
_pop_regs
|
||||
add $0x10, %rsp
|
||||
iretq
|
||||
8
kernel/proc/switch.h
Normal file
8
kernel/proc/switch.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef PROC_SWITCH_H_
|
||||
#define PROC_SWITCH_H_
|
||||
|
||||
#include "vmm/vmm.h"
|
||||
|
||||
extern void proc_switch(void *newsp, PgTable *cr3);
|
||||
|
||||
#endif // PROC_SWITCH_H_
|
||||
@ -1,5 +1,5 @@
|
||||
.global hal_randnum
|
||||
hal_randnum:
|
||||
.global randcrypto_get_physrand
|
||||
randcrypto_get_physrand:
|
||||
mov $100, %ecx
|
||||
xor %eax, %eax
|
||||
|
||||
8
kernel/randcrypto/physrand.h
Normal file
8
kernel/randcrypto/physrand.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef RANDCRYPTO_PHYSDRAND_H_
|
||||
#define RANDCRYPTO_PHYSDRAND_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t randcrypto_get_physrand(void);
|
||||
|
||||
#endif // RANDCRYPTO_PHYSDRAND_H_
|
||||
@ -1,5 +1,5 @@
|
||||
#include "randcrypto.h"
|
||||
#include "uniqid.h"
|
||||
#include "randcrypto/randcrypto.h"
|
||||
#include "randcrypto/uniqid.h"
|
||||
|
||||
void randcrypto_init(void) {
|
||||
randcrypto_uniqid_init();
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "uniqid.h"
|
||||
#include "atomic.h"
|
||||
#include "randcrypto/uniqid.h"
|
||||
#include "randcrypto/physrand.h"
|
||||
#include "spinlock/spinlock.h"
|
||||
#include "hal/hal.h"
|
||||
|
||||
static const char *base62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
@ -28,7 +27,7 @@ void uniqseed(void) {
|
||||
return;
|
||||
|
||||
uint32_t seed = 0;
|
||||
int32_t r = hal_randnum();
|
||||
int32_t r = randcrypto_get_physrand();
|
||||
if (r != -1) {
|
||||
seed = (uint32_t)r;
|
||||
} else {
|
||||
@ -48,7 +47,7 @@ void randcrypto_gen_uniqid(char *out, size_t n) {
|
||||
|
||||
uniqseed();
|
||||
|
||||
int32_t r = hal_randnum();
|
||||
int32_t r = randcrypto_get_physrand();
|
||||
uint32_t extra = (r != -1) ? (uint32_t)r : uniqstate * 0x27d4eb2dU;
|
||||
|
||||
uniqstate += 0x9E3779B1u;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "rbuf.h"
|
||||
#include "rbuf/rbuf.h"
|
||||
#include "kprintf.h"
|
||||
#include "hal/hal.h"
|
||||
|
||||
void rbuf_init(RBuf *rbuf, uint8_t *buf, size_t bufsize) {
|
||||
rbuf->buffer = buf;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user