~swisschili/bluejay

d98781b75eb3eed1997b9c8e6befd3381f81b1cf — swissChili 9 months ago 36ed5d7
Abstract EXT2, add JMK Emacs integration
A .dir-locals.el => .dir-locals.el +3 -0
@@ 0,0 1,3 @@
((nil . ((eval
		  . (setq-local flycheck-clang-args
						(jmk-arguments-for (expand-file-name buffer-file-name)))))))

M .gitignore => .gitignore +5 -0
@@ 20,3 20,8 @@ doc/_build
mnt/*
doc/_dox*
.ccls*
GTAGS
GPATh
GRTAGS
GPATH
.projectile

M bin/jmk => bin/jmk +14 -1
@@ 6,8 6,21 @@ dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
root="$(dirname $dir)"
jmkscript="$root/share/jmk/jmk.m4"

disable_gtags=false

while getopts "Gh" arg; do
    case $arg in
	G) gen_gtags=false ;;
	h) echo "Please read the JMK manual for more information." ;;
	?) echo "Invalid argument"
	   exit 1 ;;
    esac
done

for file in $(find -name Jmk); do
    echo "Processing $file" > /dev/stderr
    outdir="$(dirname $file)"
    m4 -D jmk_root="$root" -D jmk_build_cmd="$0" -D jmk_build_dir="$(pwd)" "$jmkscript" "$file" > "$outdir/Makefile" || exit 1
    m4 -D jmk_root="$root" -D jmk_build_cmd="$0" -D jmk_build_dir="$(pwd)" \
       -D disable_gtags="$disable_gtags" "$jmkscript" "$file" > "$outdir/Makefile" \
       || exit 2
done

M include/kernel/dri/fs/ext2/ext2.h => include/kernel/dri/fs/ext2/ext2.h +67 -9
@@ 237,6 237,12 @@ enum
/// File type flag (used on inode->mode)
#define EXT2_F_TYPE 0xf000

const extern uchar ext2_s_to_ft[];

/// Converts the file "mode" (inode->mode, EXT2_S_*) to a file type
/// (EXT2_FT_*).
#define EXT2_S_TO_FT(s) (ext2_s_to_ft[s >> 12])

struct ext2_dirent
{
	uint inode;


@@ 258,34 264,53 @@ enum
	EXT2_FT_SYMLINK,
};

/// Read a file system block (0-indexed), if necessary multiple disk blocks
/// will be read automatically
void ext2_read_block(struct ext2_superblock *sb, void *buffer, uint block);
void ext2_write_block(struct ext2_superblock *sb, void *buffer, uint block);
/// Read a file system block (0-indexed), if necessary multiple disk
/// blocks will be read automatically
void ext2_read_block(struct ext2_superblock *sb, void *buffer,
					 uint block);
void ext2_write_block(struct ext2_superblock *sb, void *buffer,
					  uint block);

struct ext2_superblock ext2_read_superblock();

void ext2_write_superblock(struct ext2_superblock *sb);

/// Just for fun, corrupt the superblock (obviously don't actually do this)
/// Just for fun, corrupt the superblock (obviously don't actually do
/// this)
void ext2_corrupt_superblock_for_fun();

void ext2_mount(struct fs_node *where);

bool ext2_valid_filesystem();

bool ext2_find_inode(struct ext2_superblock *sb, uint number, struct ext2_inode *inode);
/**
 * @brief Get or set an inode
 * @param inode Either a pointer to the value to be read (set=false),
 * or the value to be written (set=true).
 * @param set True if the inode should be set (written), false
 * otherwise.
 */
bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
						   struct ext2_inode *inode, bool set);

bool ext2_find_inode(struct ext2_superblock *sb, uint number,
					 struct ext2_inode *inode);

bool ext2_set_inode(struct ext2_superblock *sb, uint number,
					struct ext2_inode *inode);

/// Load a block group descriptor for a certain block group
struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
	struct ext2_superblock *sb, uint block_group);

/// List the contents of a directory dir. Calls `cb` for each item. If `dir` is
/// not a directory, returns false. Otherwise returns true.
/// List the contents of a directory dir. Calls `cb` for each item. If
/// `dir` is not a directory, returns false. Otherwise returns true.
/// if cb returns true, ls will continue. Otherwise it will stop.
bool ext2_dir_ls(struct ext2_superblock *sb,
				 struct ext2_inode *dir,
				 void (*cb)(uint inode,
				 bool (*cb)(uint inode,
							const char *name,
							uint name_len,
							void *data),
				 void *data);



@@ 341,3 366,36 @@ uint ext2_first_free_inode(struct ext2_superblock *sb);

void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
						  char *name, uint name_len, uint inode, uchar type);

/**
 * Creates a hard link
 * @param dir Directory to create the hard link in
 * @param name Name of the link  to create
 * @param name_len length of name, not including (optional) NULL byte
 * @param inode Inode number of link target
 */
bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
                    char *name, uint name_len, uint inode);

/**
 * @brief Does a directory contain a certain entry?
 * @param sb Superblock
 * @param dir The directory to search in
 * @param name The name of the entry to look for
 * @param len The length of the name, not including the optional NULL byte
 * @returns True if the entry is found, false if not, or if something
 * goes wrong (ie: dir is not a directory)
 */
bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
					   char *name, uint len);

/**
 * @brief Find an entry in a directory
 * @param dir Directory to search in
 * @param name Name of file
 * @param name_len Length of name, not including (optional) NULL byte.
 * @returns 0 if no entry could be found, otherwise inode number for
 * that entry
 */
uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
				   char *name, uint name_len);

M include/kernel/io.h => include/kernel/io.h +2 -0
@@ 73,6 73,8 @@ int strcmp(char *a, char *b);
 * @returns the length of null-terminated string a.
 */
uint strlen(char *a);
uint strnlen(char *s, size_t len);
int strncmp(char *a, char *b, size_t len);

bool isdigit(char c);
/**

M include/kernel/kint.h => include/kernel/kint.h +2 -0
@@ 21,6 21,8 @@ enum
#define MIN(a, b) ((a)>(b)?(b):(a))
#define MAX(a, b) ((a)>(b)?(a):(b))

#define UNUSED(val) ((void)(val));

/// Pads num to an integer size boundary
#define PAD(num) ((num + 3) & (~0b11))


A share/jmk/dir-locals.el => share/jmk/dir-locals.el +3 -0
@@ 0,0 1,3 @@
((nil . ((eval
		  . (setq-local flycheck-clang-args
						(jmk-arguments-for (expand-file-name buffer-file-name)))))))

A share/jmk/jmk-flycheck.el => share/jmk/jmk-flycheck.el +37 -0
@@ 0,0 1,37 @@
(defun jmk-find-parent-makefile (p)
  "Find the parent makefile of file P."
  (let ((path (or p (expand-file-name "."))))
	(while (not (or (string= path "/")
					(file-exists-p (concat path "/Makefile"))))
	  (setq path (expand-file-name (concat path "/.."))))
	(unless (string= path "/")
	  (concat path "/Makefile"))))

(defun jmk-find-makefile (p)
  "Find the makefile for the source file P.
/a/b/src/hello.c -> /a/b/src/Makefile
/a/b/include/hello.h -> /a/b/src/Makefile
Returns nil if nothing can be found"
  (if-let ((makefile (jmk-find-parent-makefile p)))
	  makefile
	(jmk-find-parent-makefile (replace-regexp-in-string
							   (regexp-quote "include")
							   "src" p nil 'literal))))

(defun jmk-arguments-for (p)
  (if-let (path (jmk-find-makefile p))
	  (split-string (shell-command-to-string
					 (concat "make -f " path " show_cflags")) " ")
	nil))

(defun jmk-includes-for (p)
  (let* ((args (jmk-arguments-for p))
		 (includes (cl-remove-if-not (lambda (arg)
									   (string-prefix-p "-I" arg))
									 args))
		 (names (mapcar (lambda (arg)
						  (string-trim (substring arg 2)))
						includes)))
	(message "includes: %s" names)
	names))


M share/jmk/jmk.m4 => share/jmk/jmk.m4 +17 -4
@@ 9,9 9,12 @@ define(`_arg1', `$1')
define(`_foreach', `ifelse(`$2', `()', `',
  `define(`$1', _arg1$2)$3`'$0(`$1', (shift$2), `$3')')')

define(status_log, `	@printf " \e[1;34m%8s\e[m  %s\n" "$1" "$2"')
define(status_log, `	@printf " \e[1;34m%8s\e[m  %s\n" "$1" "$2" > /dev/stderr')
define(DO_MAKE, `$(MAKE) --no-print-directory MAKEFILE_DEPTH="$$(( $(MAKEFILE_DEPTH) + 1))"')

define(gtags_path, $(ROOT)/GTAGS)
define(gen_gtags, ifelse(disable_gtags,true,,cd $(ROOT) && gtags))

define(init,
`jmk_project := $1
jmk_target = ifelse(`$#', 2, $2, $1)


@@ 49,10 52,10 @@ define(dollar_at, `ident($)ident(@)')

dnl archetype enables a language archetype
define(archetype,
    `ifelse($1, c, `.c.o:
    `ifelse($1, c, `.c.o: gtags_path
status_log(CC, $<)
	@$(CC) -c $< -o dollar_at $(CFLAGS)',
        $1, asm, `.s.o:
        $1, asm, `.s.o: gtags_path
status_log(AS, $<)
	@$(ASM) $(ASMFLAGS) $< -o dollar_at')')



@@ 81,14 84,17 @@ define(type,
    `ifelse($1, executable,
`$(jmk_target): $(OBJECTS)
status_log(LD, dollar_at)
	@gen_gtags
	@$(CC) -o dollar_at $^ $(CFLAGS)',
    $1, static_lib,
`$(jmk_target): $(OBJECTS)
status_log(AR, dollar_at)
	@gen_gtags
	@ar rcs dollar_at $^',
    $1, custom_link,
`$(jmk_target): $(OBJECTS)
status_log(LD, dollar_at)
	@gen_gtags
	@$(LD) $(LDFLAGS) -o dollar_at $^')')

define(option,


@@ 107,6 113,13 @@ Makefile: Jmk
status_log(JMK, jmk_build_dir)
	@cd "jmk_build_dir" && jmk_build_cmd

.PHONY: $(jmk_libs_phony) $(jmk_custom_phony) $(jmk_clean_libs) clean all')
gtags_path:
status_log(GTAGS,)
	gen_gtags

show_cflags:
	@echo $(CFLAGS)

.PHONY: $(jmk_libs_phony) $(jmk_custom_phony) $(jmk_clean_libs) clean all show_cflags')

divert(0)dnl

M src/kernel/Jmk => src/kernel/Jmk +3 -1
@@ 1,3 1,5 @@
# -*- mode:makefile -*-

init(kernel, kernel.elf)

preset(freestanding)


@@ 25,7 27,7 @@ test_defines = $(TEST:%=-DTEST_%)

FS ?= ext2

CFLAGS += -I $(ROOT)/include/kernel $(test_defines) -O0
CFLAGS += -I$(ROOT)/include/kernel $(test_defines) -O0

LDFLAGS += -Tlink.ld -melf_i386
ASMFLAGS += -felf -Fdwarf

M src/kernel/dri/fs/ext2/ext2.c => src/kernel/dri/fs/ext2/ext2.c +165 -19
@@ 5,6 5,20 @@
#include <kint.h>
#include <log.h>

#define F(f,t) [EXT2_S_##f >> 12] = EXT2_FT_##t,
const uchar ext2_s_to_ft[] =
{
	0,
	F(IFSOCK, SOCK)
	F(IFLINK, SYMLINK)
	F(IFREG, REGULAR_FILE)
	F(IFBLK, BLKDEV)
	F(IFDIR, DIR)
	F(IFCHR, CHRDEV)
	F(IFIFO, FIFO)
};
#undef F

inline uint ext2_block_size(struct ext2_superblock *sb)
{
	return 1024 << sb->block_size_shift;


@@ 86,11 100,11 @@ struct ext2_block_group_descriptor ext2_load_block_group_descriptor(
	return descriptors[bgd_offset];
}

static void print_entry(uint inode, const char *name, void *sb)
static bool print_entry(uint inode, const char *name, uint l, void *sb)
{
	kprintf("%d\t %s\n", inode, name);

	return;
	return true;

	struct ext2_inode in;



@@ 106,11 120,13 @@ static void print_entry(uint inode, const char *name, void *sb)
		}
	}

	return;
	return true;
}

void ext2_mount(struct fs_node *where)
{
	UNUSED(where)

	struct ext2_superblock sb = ext2_read_superblock();

	kprintf(DEBUG "EXT2 magic = 0x%x\n", sb.signature);


@@ 128,8 144,7 @@ void ext2_mount(struct fs_node *where)

		char *name = "hello-hl.txt";
		kprintf(INFO "Creating hard link %s -> hello.txt\n", name);
		ext2_insert_into_dir(&sb, &root, name, strlen(name), 12,
							 EXT2_FT_REGULAR_FILE);
		ext2_hard_link(&sb, &root, name, strlen(name), 12);

		kprintf("ls /\n");
		kprintf("inode\t name\n");


@@ 168,8 183,8 @@ void ext2_corrupt_superblock_for_fun()
	ext2_write_superblock(&sb);
}

bool ext2_find_inode(struct ext2_superblock *sb, uint number,
					 struct ext2_inode *inode)
bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
						   struct ext2_inode *inode, bool set)
{
	if (number == 0)
		return false;


@@ 181,38 196,60 @@ bool ext2_find_inode(struct ext2_superblock *sb, uint number,
	struct ext2_block_group_descriptor descriptor =
		ext2_load_block_group_descriptor(sb, block_group);

	// kprintf(DEBUG "Descriptor inode_table = 0x%x\n",
	// descriptor.inode_table_start_block);

	// We need to figure out what FS block the inode is on, we know how many
	// inodes there are total in this BGD and the number per page, so this is
	// simple.

	const uint block_size = ext2_block_size(sb);

	const uint inodes_per_block = block_size / sizeof(struct ext2_inode);
	const uint inodes_per_block =
		block_size / sizeof(struct ext2_inode);

	uint inode_block = local_index / inodes_per_block;
	uint inode_index = local_index % inodes_per_block;

	struct ext2_inode inodes[block_size / sizeof(struct ext2_inode)];

	ext2_read_block(sb, inodes,
					descriptor.inode_table_start_block + inode_block);
	const uint fs_block = descriptor.inode_table_start_block +
		inode_block;

	ext2_read_block(sb, inodes, fs_block);

	if (set)
	{
		inodes[inode_index] = *inode;

	*inode = inodes[inode_index];
		ext2_write_block(sb, inodes, fs_block);
	}
	else
	{
		*inode = inodes[inode_index];
	}

	return true;
}

bool ext2_find_inode(struct ext2_superblock *sb, uint number,
					 struct ext2_inode *inode)
{
	return ext2_get_or_set_inode(sb, number, inode, false);
}

bool ext2_set_inode(struct ext2_superblock *sb, uint number,
					struct ext2_inode *inode)
{
	return ext2_get_or_set_inode(sb, number, inode, true);
}

bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
				 void (*cb)(uint inode, const char *name, void *data),
				 bool (*cb)(uint inode, const char *name, uint name_len,
							void *data),
				 void *data)
{
	if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
		return false;

	for (int i = 0; i < dir->num_blocks; i++)
	for (uint i = 0; i < dir->num_blocks; i++)
	{
		uchar buffer[ext2_block_size(sb)];
		ext2_read_inode_block(sb, dir, buffer, i);


@@ 233,8 270,8 @@ bool ext2_dir_ls(struct ext2_superblock *sb, struct ext2_inode *dir,
				memcpy(name, ent->name, name_len);
				name[name_len] = '\0';

				// kprintf("@ b=%d,ent=%p\n", i, (uint)ent - (uint)buffer);
				cb(ent->inode, name, data);
				if (!cb(ent->inode, name, name_len, data))
					return true;
			}

			ent = (void *)(((uint)(void *)ent) + ent->rec_len);


@@ 256,6 293,35 @@ static void ext2_show_dirent(struct ext2_dirent *ent)
			ent->name, ent->rec_len);
}

bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
                    char *name, uint name_len, uint inode)
{
	struct ext2_inode in;

	if (!ext2_dir_contains(sb, dir, name, name_len) &&
		ext2_find_inode(sb, inode, &in))
	{
		if ((dir->mode & 0xf000) != EXT2_S_IFDIR)
		{
			return false;
		}

		// Increment the reference count to this inode
		in.links_count++;
		ext2_set_inode(sb, inode, &in);

		// Insert it into the directory
		uchar type = EXT2_S_TO_FT(in.mode);
		ext2_insert_into_dir(sb, dir, name, name_len, inode, type);

		return true;
	}
	else
	{
		return false;
	}	
}

void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
						  char *name, uint name_len, uint inode, uchar type)
{


@@ 303,7 369,8 @@ void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
				PAD(ent->name_len + sizeof(struct ext2_dirent));
			uint available_size = ent->rec_len - this_min_size;

			// kprintf(",%d=%d/%d", ent->name_len, this_min_size, available_size);
			// kprintf(",%d=%d/%d", ent->name_len, this_min_size,
			// available_size);

			if (available_size >= min_size)
			{


@@ 560,3 627,82 @@ uint ext2_first_free_block(struct ext2_superblock *sb)

	return 0;
}

struct ext2_dir_contains_data
{
	char *name;
	uint len;
	bool found;
};

static bool ext2_dir_contains_cb(uint inode, const char *name,
								uint name_len,
								struct ext2_dir_contains_data *d)
{
	if (strncmp((char *)name, d->name, MIN(name_len, d->len)) == 0)
	{
		d->found = true;
		return false;
	}

	return true;
}

bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
					   char *name, uint len)
{
	if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
	{
		return false;
	}

	struct ext2_dir_contains_data d =
		{
			.name = name,
			.len = len,
			.found = false,
		};

	ext2_dir_ls(sb, dir, ext2_dir_contains_cb, &d);

	return d.found;
}

struct ext2_dir_find_data
{
	char *name;
	uint len;
	uint inode;
};

bool ext2_dir_find_cb(uint inode, const char *name, uint len,
					  struct ext2_dir_find_data *d)
{
	if (strncmp((char *)name, d->name, MIN(len, d->len)) == 0)
	{
		d->inode = inode;
		return false;
	}

	return true;
}

uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
				   char *name, uint name_len)
{
	if ((dir->mode & EXT2_F_TYPE) != EXT2_S_IFDIR)
	{
		return false;
	}

	struct ext2_dir_find_data d =
		{
			.name = name,
			.len = name_len,
			.inode = 0,
		};

	ext2_dir_ls(sb, dir, ext2_dir_find_cb, &d);

	return d.inode;
}

M src/kernel/io.c => src/kernel/io.c +33 -0
@@ 30,6 30,13 @@ ushort inw(ushort port)
	return ret;
}

struct ext2_dir_contains_data
{
	char *name;
	uint len;
	bool found;
};

void outl(ushort port, uint val)
{
	asm("outl %1, %0" : : "dN"(port), "a"(val));


@@ 85,6 92,32 @@ uint strlen(char *a)
	return i;
}

uint strnlen(char *s, size_t len)
{
	int i;

	for (i = 0; s[i] && i < len; i++)
	{
	}

	return i;
}

int strncmp(char *a, char *b, size_t len)
{
	int al = strnlen(a, len), bl = strnlen(b, len);

	if (al != bl)
		return bl - al;

	for (int i = 0; i < al; i++)
	{
		if (a[i] != b[i])
			return -1;
	}
	return 0;
}

int strcmp(char *a, char *b)
{
	int al = strlen(a), bl = strlen(b);