proof-of-concept file reading from tar-formatted disk
This commit is contained in:
parent
b0d57fcb54
commit
01d3acbac9
7 changed files with 186 additions and 45 deletions
5
Makefile
5
Makefile
|
|
@ -82,7 +82,12 @@ drive.img:
|
|||
truncate -s 16M $@
|
||||
|
||||
drive-virtio.img:
|
||||
echo "Hello World!" > a.txt
|
||||
echo "Goodbye World!" > b.txt
|
||||
tar --format=v7 -cvf $@ a.txt b.txt
|
||||
truncate -s 16M $@
|
||||
rm a.txt
|
||||
rm b.txt
|
||||
|
||||
clean:
|
||||
rm -rf build/*
|
||||
|
|
|
|||
|
|
@ -3,23 +3,19 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct tar_header {
|
||||
char *name;
|
||||
uint8_t UNUSED_mode_owner;
|
||||
uint8_t UNUSED_mode_group;
|
||||
uint16_t UNUSED_owner_id;
|
||||
uint16_t UNUSED_group_id;
|
||||
uint64_t size;
|
||||
uint64_t UNUSED_mtime;
|
||||
uint64_t UNUSED_checksum;
|
||||
#define TAR_LINK_HARD 1
|
||||
#define TAR_LINK_SYM 2
|
||||
uint8_t link_indicator;
|
||||
char *link_name;
|
||||
void *data;
|
||||
};
|
||||
|
||||
bool tar_get_file(const char *name, struct tar_header *hd_out);
|
||||
bool tar_get_file_info_in_mem(
|
||||
const char *name,
|
||||
void *tar_start,
|
||||
void *tar_end,
|
||||
uint64_t *size_out, void **data_out);
|
||||
bool tar_get_file_info_custom(
|
||||
const char *name,
|
||||
size_t tar_num_blocks,
|
||||
uint8_t *(*get_block)(uint64_t,void*),
|
||||
void (*put_block)(uint64_t,void*),
|
||||
void *cbdata,
|
||||
uint64_t *size_out, uint64_t *bno_out);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -116,10 +116,17 @@ struct blk_req {
|
|||
uint64_t num_sectors;
|
||||
struct pa data;
|
||||
};
|
||||
#define BLK_READ(s, d, n) ((struct blk_req){ .type = BLK_REQ_READ, .sector = s, .data = d, .num_sectors = n })
|
||||
#define BLK_WRITE(s, d, n) ((struct blk_req){ .type = BLK_REQ_WRITE, .sector = s, .data = d, .num_sectors = n }) // make copy because we free mem
|
||||
#define BLK_READ(s, n, d) ((struct blk_req){ .type = BLK_REQ_READ, .sector = s, .num_sectors = n, .data = d })
|
||||
#define BLK_WRITE(s, n, d) ((struct blk_req){ .type = BLK_REQ_WRITE, .sector = s, .num_sectors = n, .data = d })
|
||||
#define BLK_FLUSH() ((struct blk_req){ .type = BLK_REQ_FLUSH })
|
||||
|
||||
// Queues an operation on the device.
|
||||
// See macros above to specify an operation
|
||||
// Returns as soon as request is submitted, does not wait until operation is complete.
|
||||
// Once complete, `cb` is called.
|
||||
// `req.data` must be physically contiguous and at least of size `512 * req.num_sectors`.
|
||||
// It must not be freed before the callback is called. It may be freed inside the callback.
|
||||
// Requests may be completed out of order, so `cb` may also be called out of order.
|
||||
enum blk_queue_result
|
||||
virtio_blk_queue_req(
|
||||
struct virtio_blk_context *ctx,
|
||||
|
|
|
|||
13
src/font.c
13
src/font.c
|
|
@ -1,20 +1,27 @@
|
|||
#include "font.h"
|
||||
|
||||
#include "bootboot.h"
|
||||
#include "sff.h"
|
||||
#include "std.h"
|
||||
#include "tar.h"
|
||||
#include "texture.h"
|
||||
#include "address.h"
|
||||
|
||||
extern BOOTBOOT bootboot;
|
||||
|
||||
bool font_load(const char *name, font_handle *out) {
|
||||
if (name == NULL || out == NULL) {
|
||||
return false;
|
||||
}
|
||||
struct tar_header hd;
|
||||
bool success = tar_get_file(name, &hd);
|
||||
uint64_t size;
|
||||
void *data;
|
||||
char *initrd_ptr = pa_to_pointer(pa_from_value(bootboot.initrd_ptr));
|
||||
char *initrd_end = initrd_ptr + bootboot.initrd_size;
|
||||
bool success = tar_get_file_info_in_mem(name, initrd_ptr, initrd_end, &size, &data);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
success = sff_decode(hd.data, hd.size, out);
|
||||
success = sff_decode(data, size, out);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
|||
65
src/kernel.c
65
src/kernel.c
|
|
@ -12,6 +12,7 @@
|
|||
#include "cpu.h"
|
||||
#include "texture.h"
|
||||
#include "time.h"
|
||||
#include "tar.h"
|
||||
|
||||
#include "x86_64/asm.h"
|
||||
#include "x86_64/ps2_driver.h"
|
||||
|
|
@ -85,6 +86,51 @@ void mycb(struct blk_req req, void* userdata) {
|
|||
slab_cache_free(pa_to_pointer(req.data));
|
||||
}
|
||||
|
||||
struct slab_cache sector_cache;
|
||||
struct cache_entry {
|
||||
bool used;
|
||||
bool done;
|
||||
uint64_t bno;
|
||||
struct pa data;
|
||||
} re1, re2;
|
||||
|
||||
void get_block_done(struct blk_req req, void* userdata) {
|
||||
struct cache_entry *entry = userdata;
|
||||
entry->done = true;
|
||||
}
|
||||
uint8_t *get_block(uint64_t bno,void *cbdata) {
|
||||
struct virtio_blk_context *ctx = cbdata;
|
||||
struct pa data = pa_from_pointer(slab_cache_alloc(§or_cache));
|
||||
volatile struct cache_entry *entry;
|
||||
if (!re1.used) {
|
||||
entry = &re1;
|
||||
} else {
|
||||
ASSERT(!re2.used);
|
||||
entry = &re2;
|
||||
}
|
||||
entry->used = true;
|
||||
entry->done = false;
|
||||
entry->bno = bno;
|
||||
entry->data = data;
|
||||
virtio_blk_queue_req(ctx, BLK_READ(bno, 1, data), get_block_done, entry);
|
||||
|
||||
while (!entry->done) {
|
||||
virtio_blk_on_used_notif(ctx);
|
||||
}
|
||||
return pa_to_pointer(entry->data);
|
||||
}
|
||||
void put_block(uint64_t bno, void *cbdata) {
|
||||
struct cache_entry *entry;
|
||||
if (re1.used && re1.bno == bno) {
|
||||
entry = &re1;
|
||||
} else {
|
||||
ASSERT(re2.used && re2.bno == bno);
|
||||
entry = &re2;
|
||||
}
|
||||
slab_cache_free(pa_to_pointer(entry->data));
|
||||
entry->used = false;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
__asm__("sti");
|
||||
|
||||
|
|
@ -114,21 +160,14 @@ void main(void) {
|
|||
struct virtio_blk_context ctx;
|
||||
virtio_blk_device_init(bdf, &ctx);
|
||||
|
||||
struct slab_cache sector_cache;
|
||||
slab_cache_init_with_align(§or_cache, 512, 512, NULL, NULL);
|
||||
|
||||
#define NR 50
|
||||
for (int i = 0; i < NR; i++) {
|
||||
struct pa addr = pa_from_pointer(slab_cache_alloc(§or_cache));
|
||||
ASSERT(addr.value != 0);
|
||||
enum blk_queue_result res = virtio_blk_queue_req(&ctx, BLK_READ(i, addr, 1), mycb, NULL);
|
||||
ASSERT(res == BLK_QUEUE_RESULT_OK);
|
||||
}
|
||||
|
||||
struct virtq_used *used = ctx.used;
|
||||
while (LE16_TO_CPU(used->idx) < NR) ; // wait. TODO interrupts
|
||||
|
||||
virtio_blk_on_used_notif(&ctx);
|
||||
uint64_t size;
|
||||
uint64_t bno;
|
||||
ASSERT(tar_get_file_info_custom("b.txt", ctx.num_sectors, get_block, put_block, &ctx,
|
||||
&size, &bno));
|
||||
ASSERT(!re1.used && !re2.used);
|
||||
printlinef("found file: size %lu bno %lu", size, bno);
|
||||
|
||||
slab_cache_destroy(§or_cache);
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ bool slab_cache_new_slab(struct slab_cache *cache) {
|
|||
// never returns NULL.
|
||||
static void *slab_obj_alloc(struct slab *slab) {
|
||||
ASSERT(slab != NULL);
|
||||
ASSERT(slab->magic == SLAB_MAGIC);
|
||||
ASSERT(slab->free_stack != NULL && slab->free_count > 0);
|
||||
slab->free_count--;
|
||||
struct free_stack *free = slab->free_stack;
|
||||
|
|
@ -149,6 +150,7 @@ void *slab_cache_alloc(struct slab_cache *cache) {
|
|||
|
||||
struct slab *slab = cache->empty_slabs;
|
||||
ASSERT(slab != NULL);
|
||||
ASSERT(slab->magic == SLAB_MAGIC);
|
||||
|
||||
// move previously empty slab to partial or full list
|
||||
cache->empty_slabs = slab->next;
|
||||
|
|
@ -172,9 +174,11 @@ static void slab_cache_remove_slab_from_list(
|
|||
{
|
||||
ASSERT(cache != NULL);
|
||||
ASSERT(slab != NULL);
|
||||
ASSERT(slab->magic == SLAB_MAGIC);
|
||||
ASSERT(list_ptr != NULL);
|
||||
struct slab *prev = NULL;
|
||||
for (struct slab *curr = *list_ptr; curr != NULL; curr = curr->next) {
|
||||
ASSERT(curr->magic == SLAB_MAGIC);
|
||||
if (curr == slab) {
|
||||
if (prev != NULL) {
|
||||
prev->next = slab->next;
|
||||
|
|
@ -192,6 +196,7 @@ static void slab_cache_remove_slab_from_list(
|
|||
static void slab_obj_free(struct slab *slab, void *obj) {
|
||||
ASSERT(slab != NULL);
|
||||
ASSERT(obj != NULL);
|
||||
ASSERT(slab->magic == SLAB_MAGIC);
|
||||
ASSERT(slab->free_count < slab->cache->num_slots_per_slab);
|
||||
ASSERT(PAGE_BASE(obj) == (void*)slab);
|
||||
|
||||
|
|
@ -214,6 +219,7 @@ static void slab_cache_return_slab_to_kernel(
|
|||
{
|
||||
ASSERT(cache != NULL);
|
||||
ASSERT(slab != NULL);
|
||||
ASSERT(slab->magic == SLAB_MAGIC);
|
||||
ASSERT(slab->free_count == cache->num_slots_per_slab);
|
||||
uint8_t *raw = (uint8_t*)slab;
|
||||
uint8_t * const page_start = raw;
|
||||
|
|
@ -279,6 +285,7 @@ void slab_cache_return_unused_mem(struct slab_cache *cache) {
|
|||
ASSERT(cache != NULL);
|
||||
struct slab *slab = cache->empty_slabs;
|
||||
while (slab != NULL) {
|
||||
ASSERT(slab->magic == SLAB_MAGIC);
|
||||
struct slab *next_slab = slab->next; // read next pointer before freeing mem
|
||||
slab_cache_return_slab_to_kernel(cache, slab);
|
||||
slab = next_slab;
|
||||
|
|
|
|||
100
src/tar.c
100
src/tar.c
|
|
@ -1,9 +1,22 @@
|
|||
#include "address.h"
|
||||
#include "std.h"
|
||||
#include "tar.h"
|
||||
#include "bootboot.h"
|
||||
|
||||
extern BOOTBOOT bootboot; // see bootboot.h
|
||||
struct tar_header {
|
||||
char *name;
|
||||
uint8_t UNUSED_mode_owner;
|
||||
uint8_t UNUSED_mode_group;
|
||||
uint16_t UNUSED_owner_id;
|
||||
uint16_t UNUSED_group_id;
|
||||
uint64_t size;
|
||||
uint64_t UNUSED_mtime;
|
||||
uint64_t UNUSED_checksum;
|
||||
#define TAR_LINK_HARD 1
|
||||
#define TAR_LINK_SYM 2
|
||||
uint8_t link_indicator;
|
||||
char *link_name;
|
||||
};
|
||||
|
||||
|
||||
#define IS_OCTAL(c) ((c) >= '0' && (c) <= '7')
|
||||
#define IS_DEC(c) ((c) >= '0' && (c) <= '9')
|
||||
|
|
@ -24,14 +37,18 @@ static void tar_header_parse(void *addr, struct tar_header *hd_out) {
|
|||
char lin = *((char *)addr + 156);
|
||||
hd_out->link_indicator = IS_DEC(lin) ? lin - '0' : lin;
|
||||
hd_out->link_name = (char *)addr + 157;
|
||||
hd_out->data = (char *)addr + 512;
|
||||
}
|
||||
|
||||
#define SYM_FOLLOW_CAP 100
|
||||
|
||||
bool tar_get_file(const char *name, struct tar_header *hd_out) {
|
||||
char *initrd_ptr = pa_to_pointer(pa_from_value(bootboot.initrd_ptr));
|
||||
char *initrd_end = initrd_ptr + bootboot.initrd_size;
|
||||
bool tar_get_file_info_in_mem(
|
||||
const char *name,
|
||||
void *tar_start,
|
||||
void *tar_end,
|
||||
uint64_t *size_out, void **data_out)
|
||||
{
|
||||
uint8_t *ptr = tar_start;
|
||||
uint8_t *end = tar_end;
|
||||
unsigned int hard_follow_count = 0;
|
||||
unsigned int sym_follow_count = 0;
|
||||
struct tar_header hd;
|
||||
|
|
@ -40,8 +57,8 @@ find_begin:
|
|||
ASSERT(hard_follow_count <= 1);
|
||||
ASSERT(sym_follow_count < SYM_FOLLOW_CAP);
|
||||
|
||||
while (initrd_ptr < initrd_end) {
|
||||
tar_header_parse(initrd_ptr, &hd);
|
||||
while (ptr < end) {
|
||||
tar_header_parse(ptr, &hd);
|
||||
if (streq(hd.name, name)) {
|
||||
if (hd.link_indicator == TAR_LINK_HARD) {
|
||||
name = hd.link_name;
|
||||
|
|
@ -52,12 +69,75 @@ find_begin:
|
|||
sym_follow_count += 1;
|
||||
goto find_begin;
|
||||
} else {
|
||||
memcpy(hd_out, &hd, sizeof(hd));
|
||||
*size_out = hd.size;
|
||||
*data_out = ptr + 512;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
initrd_ptr += 512 + ((hd.size + 511) & ~511);
|
||||
ptr += 512 + ((hd.size + 511) & ~511);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tar_get_file_info_custom(
|
||||
const char *name,
|
||||
size_t tar_num_blocks,
|
||||
uint8_t *(*get_block)(uint64_t,void*),
|
||||
void (*put_block)(uint64_t,void*),
|
||||
void *cbdata,
|
||||
uint64_t *size_out, uint64_t *bno_out)
|
||||
{
|
||||
size_t bno = 0;
|
||||
unsigned int hard_follow_count = 0;
|
||||
unsigned int sym_follow_count = 0;
|
||||
struct tar_header hd;
|
||||
bool use_other_block = false;
|
||||
size_t bno_other;
|
||||
|
||||
find_begin:
|
||||
ASSERT(hard_follow_count <= 1);
|
||||
ASSERT(sym_follow_count < SYM_FOLLOW_CAP);
|
||||
|
||||
while (bno < tar_num_blocks) {
|
||||
uint8_t *ptr = get_block(bno, cbdata);
|
||||
tar_header_parse(ptr, &hd);
|
||||
if (streq(hd.name, name)) {
|
||||
if (hd.link_indicator == TAR_LINK_HARD) {
|
||||
name = hd.link_name;
|
||||
hard_follow_count += 1;
|
||||
if (use_other_block) {
|
||||
put_block(bno_other, cbdata);
|
||||
}
|
||||
use_other_block = true;
|
||||
bno_other = bno;
|
||||
goto find_begin;
|
||||
} else if (hd.link_indicator == TAR_LINK_SYM) {
|
||||
name = hd.link_name;
|
||||
sym_follow_count += 1;
|
||||
if (use_other_block) {
|
||||
put_block(bno_other, cbdata);
|
||||
}
|
||||
use_other_block = true;
|
||||
bno_other = bno;
|
||||
goto find_begin;
|
||||
} else {
|
||||
*size_out = hd.size;
|
||||
*bno_out = bno + 1;
|
||||
if (use_other_block) {
|
||||
put_block(bno_other, cbdata);
|
||||
}
|
||||
put_block(bno, cbdata);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
put_block(bno, cbdata);
|
||||
bno += 1 + ((hd.size + 511) >> 12);
|
||||
}
|
||||
}
|
||||
if (use_other_block) {
|
||||
put_block(bno_other, cbdata);
|
||||
}
|
||||
put_block(bno, cbdata);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue