meta: rename

This commit is contained in:
2024-11-02 11:31:51 +00:00
parent 065fdeec65
commit 62ec4c93ab
140 changed files with 422 additions and 857 deletions
+14
View File
@@ -0,0 +1,14 @@
#ifndef MANGO_ARG_H_
#define MANGO_ARG_H_
#include <stdbool.h>
#include <mango/status.h>
#define CMDLINE_MAX 4096
extern kern_status_t parse_cmdline(const char *cmdline);
extern const char *arg_value(const char *arg_name);
extern bool arg_is_set(const char *arg_name);
#endif
+35
View File
@@ -0,0 +1,35 @@
#ifndef MANGO_BITMAP_H_
#define MANGO_BITMAP_H_
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define BITS_PER_WORD (8 * sizeof(unsigned long))
#define __DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITMAP_WORDS(nbits) __DIV_ROUND_UP(nbits, BITS_PER_WORD)
#define BITMAP_NPOS ((unsigned int)-1)
#define DECLARE_BITMAP(name, nbits) unsigned long name[BITMAP_WORDS(nbits)]
extern void bitmap_zero(unsigned long *map, unsigned long nbits);
extern void bitmap_fill(unsigned long *map, unsigned long nbits);
extern void bitmap_set(unsigned long *map, unsigned long bit);
extern void bitmap_clear(unsigned long *map, unsigned long bit);
extern bool bitmap_check(unsigned long *map, unsigned long bit);
extern unsigned int bitmap_count_set(unsigned long *map, unsigned long nbits);
extern unsigned int bitmap_count_clear(unsigned long *map, unsigned long nbits);
extern unsigned int bitmap_highest_set(unsigned long *map, unsigned long nbits);
extern unsigned int bitmap_highest_clear(unsigned long *map, unsigned long nbits);
extern unsigned int bitmap_lowest_set(unsigned long *map, unsigned long nbits);
extern unsigned int bitmap_lowest_clear(unsigned long *map, unsigned long nbits);
#ifdef __cplusplus
}
#endif
#endif
+36
View File
@@ -0,0 +1,36 @@
#ifndef MANGO_BLOCK_H_
#define MANGO_BLOCK_H_
#include <mango/types.h>
#include <mango/btree.h>
#include <mango/locks.h>
#include <mango/status.h>
#include <stdbool.h>
enum block_device_flags {
BLOCK_DEVICE_NO_BCACHE = 0x01u,
};
struct bcache {
unsigned int b_sector_size;
unsigned int b_sectors_per_page;
struct btree b_pagetree;
};
struct bcache_sector {
struct vm_page *sect_page;
unsigned int sect_index;
void *sect_buf;
bool sect_present;
};
extern struct bcache *bcache_create(unsigned int block_size);
extern void bcache_destroy(struct bcache *cache);
extern kern_status_t bcache_init(struct bcache *cache, unsigned int block_size);
extern void bcache_deinit(struct bcache *cache);
extern kern_status_t bcache_get(struct bcache *cache, sectors_t at, bool create, struct bcache_sector *out);
extern void bcache_mark_present(struct bcache_sector *sect);
#endif
+381
View File
@@ -0,0 +1,381 @@
/*
The Clear BSD License
Copyright (c) 2023 Max Wash
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
*/
#ifndef MANGO_BTREE_H_
#define MANGO_BTREE_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* if your custom structure contains a struct btree_node (i.e. it can be part of a btree),
you can use this macro to convert a struct btree_node* to a your_type*
@param t the name of your custom type (something that can be passed to offsetof)
@param m the name of the struct btree_node member variable within your custom type.
@param v the struct btree_node pointer that you wish to convert. if this is NULL, NULL will be returned.
*/
#define BTREE_CONTAINER(t, m, v) ((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
/* defines a simple node insertion function.
this function assumes that your nodes have simple integer keys that can be compared with the usual operators.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
int key;
struct btree_node base;
}
You would use the following call to generate an insert function for a tree with this node type:
BTREE_DEFINE_SIMPLE_INSERT(struct my_tree_node, base, key, my_tree_node_insert);
Which would emit a function defined like:
static void my_tree_node_insert(struct btree *tree, struct my_tree_node *node);
@param node_type your custom tree node type. usually a structure that contains a struct btree_node member.
@param container_node_member the name of the struct btree_node member variable within your custom type.
@param container_key_member the name of the key member variable within your custom type.
@param function_name the name of the function to generate.
*/
#define BTREE_DEFINE_SIMPLE_INSERT(node_type, container_node_member, container_key_member, function_name) \
void function_name(struct btree *tree, node_type *node) \
{ \
if (!tree->b_root) { \
tree->b_root = &node->container_node_member; \
btree_insert_fixup(tree, &node->container_node_member); \
return; \
} \
\
struct btree_node *cur = tree->b_root; \
while (1) { \
node_type *cur_node = BTREE_CONTAINER(node_type, container_node_member, cur); \
struct btree_node *next = NULL; \
\
if (node->container_key_member > cur_node->container_key_member) { \
next = btree_right(cur); \
\
if (!next) { \
btree_put_right(cur, &node->container_node_member); \
break; \
} \
} else if (node->container_key_member < cur_node->container_key_member) { \
next = btree_left(cur); \
\
if (!next) { \
btree_put_left(cur, &node->container_node_member); \
break; \
} \
} else { \
return; \
} \
\
cur = next; \
} \
\
btree_insert_fixup(tree, &node->container_node_member); \
}
/* defines a node insertion function.
this function should be used for trees with complex node keys that cannot be directly compared.
a comparator for your keys must be supplied.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
complex_key_t key;
struct btree_node base;
}
You would need to define a comparator function or macro with the following signature:
int my_comparator(struct my_tree_node *a, struct my_tree_node *b);
Which implements the following:
return -1 if a < b
return 0 if a == b
return 1 if a > b
You would use the following call to generate an insert function for a tree with this node type:
BTREE_DEFINE_INSERT(struct my_tree_node, base, key, my_tree_node_insert, my_comparator);
Which would emit a function defined like:
static void my_tree_node_insert(struct btree *tree, struct my_tree_node *node);
@param node_type your custom tree node type. usually a structure that contains a struct btree_node member.
@param container_node_member the name of the struct btree_node member variable within your custom type.
@param container_key_member the name of the key member variable within your custom type.
@param function_name the name of the function to generate.
@param comparator the name of a comparator function or functional-macro that conforms to the
requirements listed above.
*/
#define BTREE_DEFINE_INSERT(node_type, container_node_member, container_key_member, function_name, comparator) \
void function_name(struct btree *tree, node_type *node) \
{ \
if (!tree->b_root) { \
tree->b_root = &node->container_node_member; \
btree_insert_fixup(tree, &node->container_node_member); \
return; \
} \
\
struct btree_node *cur = tree->b_root; \
while (1) { \
node_type *cur_node = BTREE_CONTAINER(node_type, container_node_member, cur); \
struct btree_node *next = NULL; \
int cmp = comparator(node, cur_node); \
\
if (cmp == 1) { \
next = btree_right(cur); \
\
if (!next) { \
btree_put_right(cur, &node->container_node_member); \
break; \
} \
} else if (cmp == -1) { \
next = btree_left(cur); \
\
if (!next) { \
btree_put_left(cur, &node->container_node_member); \
break; \
} \
} else { \
return; \
} \
\
cur = next; \
} \
\
btree_insert_fixup(tree, &node->container_node_member); \
}
/* defines a simple tree search function.
this function assumes that your nodes have simple integer keys that can be compared with the usual operators.
EXAMPLE:
if you have a tree node type like this:
struct my_tree_node {
int key;
struct btree_node base;
}
You would use the following call to generate a search function for a tree with this node type:
BTREE_DEFINE_SIMPLE_GET(struct my_tree_node, int, base, key, my_tree_node_get);
Which would emit a function defined like:
static struct my_tree_node *my_tree_node_get(struct btree *tree, int key);
@param node_type your custom tree node type. usually a structure that contains a struct btree_node member.
@param key_type the type name of the key embedded in your custom tree node type. this type must be
compatible with the builtin comparison operators.
@param container_node_member the name of the struct btree_node member variable within your custom type.
@param container_key_member the name of the key member variable within your custom type.
@param function_name the name of the function to generate.
*/
#define BTREE_DEFINE_SIMPLE_GET(node_type, key_type, container_node_member, container_key_member, function_name) \
node_type *function_name(struct btree *tree, key_type key) \
{ \
struct btree_node *cur = tree->b_root; \
while (cur) { \
node_type *cur_node = BTREE_CONTAINER(node_type, container_node_member, cur); \
if (key > cur_node->container_key_member) { \
cur = btree_right(cur); \
} else if (key < cur_node->container_key_member) { \
cur = btree_left(cur); \
} else { \
return cur_node; \
} \
} \
\
return NULL; \
}
/* perform an in-order traversal of a binary tree
If you have a tree defined like:
struct btree my_tree;
with nodes defined like:
struct my_tree_node {
int key;
struct btree_node base;
}
and you want to do something like:
foreach (struct my_tree_node *node : my_tree) { ... }
you should use this:
btree_foreach (struct my_tree_node, node, &my_tree, base) { ... }
@param iter_type the type name of the iterator variable. this should be the tree's node type, and shouldn't be a pointer.
@param iter_name the name of the iterator variable.
@param tree_name a pointer to the tree to traverse.
@param node_member the name of the struct btree_node member variable within the tree node type.
*/
#define btree_foreach(iter_type, iter_name, tree_name, node_member) \
for (iter_type *iter_name = BTREE_CONTAINER(iter_type, node_member, btree_first(tree_name)); \
iter_name; \
iter_name = BTREE_CONTAINER(iter_type, node_member, btree_next(&((iter_name)->node_member))))
/* perform an reverse in-order traversal of a binary tree
If you have a tree defined like:
struct btree my_tree;
with nodes defined like:
struct my_tree_node {
int key;
struct btree_node base;
}
and you want to do something like:
foreach (struct my_tree_node *node : reverse(my_tree)) { ... }
you should use this:
btree_foreach_r (struct my_tree_node, node, &my_tree, base) { ... }
@param iter_type the type name of the iterator variable. this should be the tree's node type, and shouldn't be a pointer.
@param iter_name the name of the iterator variable.
@param tree_name a pointer to the tree to traverse.
@param node_member the name of the struct btree_node member variable within the tree node type.
*/
#define btree_foreach_r(iter_type, iter_name, tree_name, node_member) \
for (iter_type *iter_name = BTREE_CONTAINER(iter_type, node_member, btree_last(tree_name)); \
iter_name; \
iter_name = BTREE_CONTAINER(iter_type, node_member, btree_prev(&((iter_name)->node_member))))
/* binary tree nodes. this *cannot* be used directly. you need to define a custom node type
that contains a member variable of type struct btree_node.
you would then use the supplied macros to define functions to manipulate your custom binary tree.
*/
struct btree_node {
struct btree_node *b_parent, *b_left, *b_right;
unsigned short b_height;
};
/* binary tree. unlike struct btree_node, you can define variables of type struct btree. */
struct btree {
struct btree_node *b_root;
};
/* re-balance a binary tree after an insertion operation.
NOTE that, if you define an insertion function using BTREE_DEFINE_INSERT or similar,
this function will automatically called for you.
@param tree the tree to re-balance.
@param node the node that was just inserted into the tree.
*/
extern void btree_insert_fixup(struct btree *tree, struct btree_node *node);
/* delete a node from a binary tree and re-balance the tree afterwards.
@param tree the tree to delete from
@param node the node to delete.
*/
extern void btree_delete(struct btree *tree, struct btree_node *node);
/* get the first node in a binary tree.
this will be the node with the smallest key (i.e. the node that is furthest-left from the root)
*/
extern struct btree_node *btree_first(struct btree *tree);
/* get the last node in a binary tree.
this will be the node with the largest key (i.e. the node that is furthest-right from the root)
*/
extern struct btree_node *btree_last(struct btree *tree);
/* for any binary tree node, this function returns the node with the next-largest key value */
extern struct btree_node *btree_next(struct btree_node *node);
/* for any binary tree node, this function returns the node with the next-smallest key value */
extern struct btree_node *btree_prev(struct btree_node *node);
/* sets `child` as the immediate left-child of `parent` */
static inline void btree_put_left(struct btree_node *parent, struct btree_node *child)
{
parent->b_left = child;
child->b_parent = parent;
}
/* sets `child` as the immediate right-child of `parent` */
static inline void btree_put_right(struct btree_node *parent, struct btree_node *child)
{
parent->b_right = child;
child->b_parent = parent;
}
/* get the immediate left-child of `node` */
static inline struct btree_node *btree_left(struct btree_node *node)
{
return node->b_left;
}
/* get the immediate right-child of `node` */
static inline struct btree_node *btree_right(struct btree_node *node)
{
return node->b_right;
}
/* get the immediate parent of `node` */
static inline struct btree_node *btree_parent(struct btree_node *node)
{
return node->b_parent;
}
/* get the height of `node`.
the height of a node is defined as the length of the longest path
between the node and a leaf node.
this count includes the node itself, so the height of a leaf node will be 1.
*/
static inline unsigned short btree_height(struct btree_node *node)
{
return node->b_height;
}
#ifdef __cplusplus
}
#endif
#endif
+27
View File
@@ -0,0 +1,27 @@
#ifndef MANGO_CLOCK_H_
#define MANGO_CLOCK_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define HZ (clock_hz())
typedef uint64_t clock_ticks_t;
extern volatile clock_ticks_t clock_ticks;
extern clock_ticks_t clock_hz(void);
extern void clock_calibrate(clock_ticks_t hz);
extern void clock_advance(clock_ticks_t ticks);
extern void clock_wait(clock_ticks_t ticks);
#ifdef __cplusplus
}
#endif
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef MANGO_COMPILER_H_
#define MANGO_COMPILER_H_
#ifdef __cplusplus
template <typename T>
T read_once(const volatile T *ptr)
{
return *ptr;
}
template <typename T>
void write_once(volatile T *ptr, T value)
{
*ptr = value;
}
#else
#define READ_ONCE(p) (*((const volatile typeof(p) *)&(p)))
#define WRITE_ONCE(p, v) *(volatile typeof(p) *)&(p) = (v)
#endif
#undef __used
#define __used __attribute__((__used__))
#undef __noreturn
#define __noreturn __attribute__((__noreturn__))
#undef __packed
#define __packed __attribute__((__packed__))
#undef __section
#define __section(name) __attribute__((__section__(name)))
#undef __aligned
#define __aligned(x) __attribute__((__aligned__(x)))
#undef __weak
#define __weak __attribute__((__weak__))
#endif
+56
View File
@@ -0,0 +1,56 @@
#ifndef MANGO_CONSOLE_H_
#define MANGO_CONSOLE_H_
/* The console system
Consoles are like simplified TTYs. Their purpose is to serve as an output
sink for messages printed using printk.
a struct console could be used to represent a serial port, UART port, or even
a text-based framebuffer display. Anything where the job of displaying
or sending text can be abstracted to a simple write() call.
A secondary purpose of consoles is to allow input. For example, a console
representing a serial port may allow both sending AND receiving over the
port.
*/
#include <mango/queue.h>
#include <mango/locks.h>
#include <mango/status.h>
#ifdef __cplusplus
extern "C" {
#endif
enum console_flags {
/* console is only used during the boot process. the console
will be automatically de-registered when the first
non-boot console is registered */
CON_BOOT = 0x01u,
};
struct console {
char c_name[16];
enum console_flags c_flags;
spin_lock_t c_lock;
void (*c_write)(struct console *, const char *, unsigned int);
int (*c_read)(struct console *, char *, unsigned int);
struct queue_entry c_list;
};
extern kern_status_t console_register(struct console *con);
extern kern_status_t console_unregister(struct console *con);
extern struct queue *get_consoles(unsigned long *flags);
extern void put_consoles(struct queue *consoles, unsigned long flags);
extern void console_write(struct console *con, const char *s, unsigned int len);
extern int console_read(struct console *con, char *s, unsigned int len);
#ifdef __cplusplus
}
#endif
#endif
+65
View File
@@ -0,0 +1,65 @@
#ifndef MANGO_CPU_H_
#define MANGO_CPU_H_
#include <mango/types.h>
#include <mango/machine/cpu.h>
#include <stdint.h>
#include <mango/sched.h>
#ifdef __cplusplus
extern "C" {
#endif
enum cpu_flags {
CPU_ONLINE = 0x01u,
};
struct cpu_data {
enum cpu_flags c_flags;
unsigned int c_id;
int c_preempt_count;
struct runqueue c_rq;
struct workqueue c_wq;
struct queue c_timers;
};
/* maximum number of processor cores that the kernel can support.
TODO move to build config option */
#define CPU_MAX 128
#define this_cpu() (ml_cpu_block_get_id(ml_this_cpu()))
extern struct cpu_data *get_this_cpu(void);
extern struct cpu_data *get_cpu(unsigned int id);
extern void put_cpu(struct cpu_data *cpu);
extern bool cpu_is_available(unsigned int cpu_id);
extern bool cpu_is_online(unsigned int cpu_id);
extern void cpu_set_available(unsigned int cpu_id);
extern void cpu_set_online(unsigned int cpu_id);
extern unsigned int cpu_nr_available(void);
extern unsigned int cpu_nr_online(void);
extern cycles_t get_cycles(void);
static inline cycles_t cycles_diff(cycles_t then, cycles_t now)
{
return now >= then ? now - then : (CYCLES_MAX - then) + now;
}
#define irq_enable() ml_int_enable()
#define irq_disable() ml_int_disable()
extern void preempt_disable(void);
extern void preempt_enable(void);
extern int preempt_count(void);
extern unsigned int cpu_get_highest_available(void);
#ifdef __cplusplus
}
#endif
#endif
+336
View File
@@ -0,0 +1,336 @@
#ifndef MANGO_DEVICE_H_
#define MANGO_DEVICE_H_
#include <mango/queue.h>
#include <mango/btree.h>
#include <mango/status.h>
#include <mango/bitmap.h>
#include <mango/object.h>
#include <mango/block.h>
#include <mango/fb.h>
#include <mango/ringbuffer.h>
struct device;
struct input_event;
struct input_event_hook;
struct tty_device;
#define DEV_NAME_MAX OBJECT_NAME_MAX
#define DEV_MODEL_NAME_MAX 64
#define DEV_MAJOR_MAX 1024
#define DEV_MINOR_MAX 1024
#define DEV_MAJOR_INVALID ((unsigned int)0)
#define DEV_MINOR_INVALID ((unsigned int)0)
#define INPUT_DEVICE_EVENT_QUEUE_SIZE 128
#define INPUT_DEVICE_MAX 4096
#define BLOCK_DEVICE_MAX 4096
#define FRAMEBUFFER_DEVICE_MAX 4096
#define BLOCK_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BLOCK ? &(dev)->blk : NULL)
#define CHAR_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? &(dev)->chr : NULL)
#define NET_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_NET ? &(dev)->net : NULL)
#define INPUT_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_INPUT ? &(dev)->input : NULL)
#define BUS_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BUS ? &(dev)->bus : NULL)
#define FRAMEBUFFER_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_FRAMEBUFFER ? &(dev)->fb : NULL)
enum device_type {
DEV_TYPE_UNKNOWN = 0,
DEV_TYPE_BLOCK,
DEV_TYPE_CHAR,
DEV_TYPE_NET,
DEV_TYPE_INPUT,
DEV_TYPE_BUS,
DEV_TYPE_FRAMEBUFFER,
};
struct iovec {
void *io_buf;
size_t io_len;
};
struct device_type_ops {
kern_status_t(*read)(struct device *, void *, size_t, size_t, size_t *, mango_flags_t);
kern_status_t(*write)(struct device *, const void *, size_t, size_t, size_t *, mango_flags_t);
kern_status_t(*register_device)(struct device *);
};
struct block_device_ops {
kern_status_t(*read_blocks)(struct device *, sectors_t, size_t *, struct iovec *, size_t, mango_flags_t);
kern_status_t(*write_blocks)(struct device *, sectors_t, size_t *, struct iovec *, size_t, mango_flags_t);
kern_status_t(*ioctl)(struct device *, unsigned int, void *);
};
struct net_device_ops {
kern_status_t(*online)(struct device *);
kern_status_t(*offline)(struct device *);
kern_status_t(*transmit)(struct device *, const void *, size_t);
kern_status_t(*ioctl)(struct device *, unsigned int, void *);
};
struct char_device_ops {
kern_status_t(*read)(struct device *, void *, size_t, size_t, size_t *, mango_flags_t);
kern_status_t(*write)(struct device *, const void *, size_t, size_t, size_t *, mango_flags_t);
};
struct input_device_ops {
kern_status_t(*ioctl)(struct device *, unsigned int, void *);
};
struct bus_device_ops {
kern_status_t(*scan)(struct device *);
};
struct framebuffer_device_ops {
kern_status_t(*set_varinfo)(struct device *, const struct framebuffer_varinfo *);
};
struct block_device {
struct block_device_ops *b_ops;
struct bcache b_cache;
enum block_device_flags b_flags;
unsigned int b_id;
unsigned int b_sector_size;
sectors_t b_capacity;
};
struct char_device {
struct char_device_ops *c_ops;
/* only valid for TTY devices */
struct tty_device *c_tty;
};
struct net_device {
struct net_device_ops *n_ops;
};
struct input_device {
struct input_device_ops *i_ops;
unsigned int i_id;
struct ringbuffer i_events;
struct queue i_hooks;
};
struct bus_device {
struct queue_entry b_buslist;
struct bus_device_ops *b_ops;
};
struct framebuffer_device {
unsigned int fb_id;
struct framebuffer_device_ops *fb_ops;
struct framebuffer_varinfo fb_varinfo;
struct framebuffer_fixedinfo fb_fixedinfo;
};
struct device {
struct object dev_base;
unsigned int dev_minor;
enum device_type dev_type;
struct device *dev_parent;
struct driver *dev_owner;
struct queue dev_children;
struct queue_entry dev_childent;
struct btree_node dev_driverent;
char dev_name[DEV_NAME_MAX];
char dev_model_name[DEV_MODEL_NAME_MAX];
void *dev_bus_priv;
void *dev_priv;
union {
struct block_device blk;
struct char_device chr;
struct net_device net;
struct input_device input;
struct bus_device bus;
struct framebuffer_device fb;
};
};
struct driver;
struct driver_ops {
/* called when a bus driver finds a device for this driver to manage. */
kern_status_t(*bind)(struct driver *, struct device *, struct device *);
/* called when driver is registered. */
kern_status_t(*install)(struct driver *);
/* called when driver is unregistered. */
kern_status_t(*uninstall)(struct driver *);
};
struct driver {
struct kext *drv_owner;
unsigned int drv_major;
DECLARE_BITMAP(drv_minors, DEV_MINOR_MAX);
char drv_name[DEV_NAME_MAX];
struct btree drv_children;
struct btree_node drv_ent;
spin_lock_t drv_lock;
void *drv_priv;
struct driver_ops *drv_ops;
};
extern kern_status_t device_init(void);
extern struct device *root_device(void);
extern struct device *misc_device(void);
extern struct device *device_alloc(void);
static inline void device_lock(struct device *dev)
{
object_lock(&dev->dev_base);
}
static inline void device_unlock(struct device *dev)
{
object_unlock(&dev->dev_base);
}
static inline void device_lock_irqsave(struct device *dev, unsigned long *flags)
{
object_lock_irqsave(&dev->dev_base, flags);
}
static inline void device_unlock_irqrestore(struct device *dev, unsigned long flags)
{
object_unlock_irqrestore(&dev->dev_base, flags);
}
extern kern_status_t device_read(struct device *dev, void *buf, size_t offset, size_t size, size_t *bytes_read, mango_flags_t flags);
extern kern_status_t device_write(struct device *dev, const void *buf, size_t offset, size_t size, size_t *bytes_written, mango_flags_t flags);
extern struct device *cast_to_device(struct object *obj);
extern struct device *generic_device_create(void);
extern struct char_device *char_device_create(void);
extern struct block_device *block_device_create(void);
extern struct net_device *net_device_create(void);
extern struct input_device *input_device_create(void);
extern struct bus_device *bus_device_create(void);
extern struct framebuffer_device *framebuffer_device_create(void);
extern struct char_device *char_device_from_generic(struct device *dev);
extern struct block_device *block_device_from_generic(struct device *dev);
extern struct net_device *net_device_from_generic(struct device *dev);
extern struct input_device *input_device_from_generic(struct device *dev);
extern struct bus_device *bus_device_from_generic(struct device *dev);
extern struct framebuffer_device *framebuffer_device_from_generic(struct device *dev);
static inline struct device *char_device_base(struct char_device *dev)
{
return (struct device *)((char *)dev - offsetof(struct device, chr));
}
static inline struct device *block_device_base(struct block_device *dev)
{
return (struct device *)((char *)dev - offsetof(struct device, blk));
}
static inline struct device *net_device_base(struct net_device *dev)
{
return (struct device *)((char *)dev - offsetof(struct device, net));
}
static inline struct device *input_device_base(struct input_device *dev)
{
return (struct device *)((char *)dev - offsetof(struct device, input));
}
static inline struct device *bus_device_base(struct bus_device *dev)
{
return (struct device *)((char *)dev - offsetof(struct device, bus));
}
static inline struct device *framebuffer_device_base(struct framebuffer_device *dev)
{
return (struct device *)((char *)dev - offsetof(struct device, fb));
}
static inline struct object *char_device_object(struct char_device *dev)
{
return &char_device_base(dev)->dev_base;
}
static inline struct object *block_device_object(struct block_device *dev)
{
return &block_device_base(dev)->dev_base;
}
static inline struct object *net_device_object(struct net_device *dev)
{
return &net_device_base(dev)->dev_base;
}
static inline struct object *input_device_object(struct input_device *dev)
{
return &input_device_base(dev)->dev_base;
}
static inline struct object *bus_device_object(struct bus_device *dev)
{
return &bus_device_base(dev)->dev_base;
}
static inline struct object *framebuffer_device_object(struct framebuffer_device *dev)
{
return &framebuffer_device_base(dev)->dev_base;
}
extern kern_status_t device_register(struct device *dev, struct driver *owner, struct device *parent);
static inline struct device *device_ref(struct device *dev)
{
return cast_to_device(object_ref(&dev->dev_base));
}
static inline void device_deref(struct device *dev)
{
object_deref(&dev->dev_base);
}
extern kern_status_t input_device_report_event(struct input_device *dev, const struct input_event *ev, bool noblock);
extern kern_status_t input_device_read(struct device *dev, void *buf, size_t offset,
size_t size, size_t *bytes_read, mango_flags_t flags);
extern kern_status_t input_device_add_hook(struct device *dev, struct input_event_hook *hook);
extern kern_status_t input_device_remove_hook(struct device *dev, struct input_event_hook *hook);
extern struct driver *driver_create(struct kext *self, const char *name);
extern kern_status_t driver_destroy(struct driver *driver);
extern kern_status_t driver_init(struct driver *driver, struct kext *self, const char *name);
extern kern_status_t driver_deinit(struct driver *driver);
extern kern_status_t driver_register(struct driver *driver);
extern kern_status_t driver_unregister(struct driver *driver);
extern unsigned int driver_alloc_minor(struct driver *driver);
extern void driver_free_minor(struct driver *driver, unsigned int minor);
extern struct device *driver_get_device(struct driver *driver, unsigned int minor);
extern kern_status_t driver_add_device(struct driver *driver, struct device *dev);
extern kern_status_t driver_remove_device(struct driver *driver, struct device *dev);
extern struct driver *system_driver(void);
extern kern_status_t framebuffer_get_fixedinfo(struct device *dev, struct framebuffer_fixedinfo *out);
extern kern_status_t framebuffer_get_varinfo(struct device *dev, struct framebuffer_varinfo *out);
extern kern_status_t framebuffer_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo);
static inline void driver_lock(struct driver *driver)
{
spin_lock(&driver->drv_lock);
}
static inline void driver_unlock(struct driver *driver)
{
spin_unlock(&driver->drv_lock);
}
static inline void driver_lock_irqsave(struct driver *driver, unsigned long *flags)
{
spin_lock_irqsave(&driver->drv_lock, flags);
}
static inline void driver_unlock_irqrestore(struct driver *driver, unsigned long flags)
{
spin_unlock_irqrestore(&driver->drv_lock, flags);
}
extern kern_status_t scan_all_buses(void);
#endif
+49
View File
@@ -0,0 +1,49 @@
#ifndef MANGO_FB_H_
#define MANGO_FB_H_
#include <stdint.h>
enum framebuffer_flags {
FB_MODE_RGB = 0x01u,
FB_MODE_VGATEXT = 0x02u,
FB_MODE_PALETTE = 0x04u,
};
struct framebuffer_bitfield {
uint32_t b_offset;
uint16_t b_length;
};
struct framebuffer_varinfo {
enum framebuffer_flags fb_flags;
uint32_t fb_xres;
uint32_t fb_yres;
uint32_t fb_bpp;
uint32_t fb_stride;
union {
struct {
uint32_t fb_xcells;
uint32_t fb_ycells;
};
struct {
struct framebuffer_bitfield fb_red;
struct framebuffer_bitfield fb_green;
struct framebuffer_bitfield fb_blue;
struct framebuffer_bitfield fb_alpha;
};
struct {
uintptr_t fb_palette_addr;
uint16_t fb_palette_nr_colours;
};
};
};
struct framebuffer_fixedinfo {
uint64_t fb_baseptr;
};
#endif
+11
View File
@@ -0,0 +1,11 @@
#ifndef MANGO_FLAGS_H_
#define MANGO_FLAGS_H_
#include <stdint.h>
typedef enum {
S_NORMAL = 0x00u,
S_NOBLOCK = 0x01u,
} mango_flags_t;
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef MANGO_INIT_H_
#define MANGO_INIT_H_
#include <mango/compiler.h>
#include <mango/machine/init.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef int (*initcall_t)(void);
#define INITLEVEL_EARLY 0
#define INITLEVEL_CORE 1
#define INITLEVEL_POSTCORE 2
#define INITLEVEL_ARCH 3
#define INITLEVEL_SUBSYS 4
#define INITLEVEL_ROOTFS 5
#define INITLEVEL_DEVICE 6
#define INITLEVEL_LATE 7
#define INITLEVEL_TESTS 8
#define early_initcall(fn) __define_initcall(fn, INITLEVEL_EARLY)
#define core_initcall(fn) __define_initcall(fn, INITLEVEL_CORE)
#define postcore_initcall(fn) __define_initcall(fn, INITLEVEL_POSTCORE)
#define arch_initcall(fn) __define_initcall(fn, INITLEVEL_ARCH)
#define subsys_initcall(fn) __define_initcall(fn, INITLEVEL_SUBSYS)
#define rootfs_initcall(fn) __define_initcall(fn, INITLEVEL_ROOTFS)
#define device_initcall(fn) __define_initcall(fn, INITLEVEL_DEVICE)
#define late_initcall(fn) __define_initcall(fn, INITLEVEL_LATE)
#define test_initcall(fn) __define_initcall(fn, INITLEVEL_TESTS)
extern void print_kernel_banner(void);
extern int do_initcalls(void);
extern int start_initlevel(int level);
#ifdef __cplusplus
}
#endif
#endif
+184
View File
@@ -0,0 +1,184 @@
#ifndef MANGO_INPUT_H_
#define MANGO_INPUT_H_
#include <stdint.h>
#include <mango/queue.h>
#include <mango/status.h>
enum input_event_hook_flags {
INPUT_HOOK_SQUASH_EVENT = 0x01u,
};
struct device;
enum input_event_type {
INPUT_TYPE_UNKNOWN = 0x00u,
INPUT_TYPE_KEY = 0x01u,
INPUT_TYPE_MOTION = 0x02u,
};
enum input_event_motion_type {
INPUT_MOTION_TYPE_MOUSE = 0x01u,
INPUT_MOTION_TYPE_SCROLL = 0x02u,
};
enum input_keycode {
KEY_UNKNOWN = 0x00u,
KEY_A = 0x01u,
KEY_B = 0x02u,
KEY_C = 0x03u,
KEY_D = 0x04u,
KEY_E = 0x05u,
KEY_F = 0x06u,
KEY_G = 0x07u,
KEY_H = 0x08u,
KEY_I = 0x09u,
KEY_J = 0x0Au,
KEY_K = 0x0Bu,
KEY_L = 0x0Cu,
KEY_M = 0x0Du,
KEY_N = 0x0Eu,
KEY_O = 0x0Fu,
KEY_P = 0x10u,
KEY_Q = 0x11u,
KEY_R = 0x12u,
KEY_S = 0x13u,
KEY_T = 0x14u,
KEY_U = 0x15u,
KEY_V = 0x16u,
KEY_W = 0x17u,
KEY_X = 0x18u,
KEY_Y = 0x19u,
KEY_Z = 0x1Au,
KEY_KEY_1 = 0x1Bu,
KEY_KEY_2 = 0x1Cu,
KEY_KEY_3 = 0x1Du,
KEY_KEY_4 = 0x1Eu,
KEY_KEY_5 = 0x1Fu,
KEY_KEY_6 = 0x20u,
KEY_KEY_7 = 0x21u,
KEY_KEY_8 = 0x22u,
KEY_KEY_9 = 0x23u,
KEY_KEY_0 = 0x24u,
KEY_ENTER = 0x25u,
KEY_ESCAPE = 0x26u,
KEY_BACKSPACE = 0x27u,
KEY_TAB = 0x28u,
KEY_SPACE = 0x29u,
KEY_MINUS = 0x2Au,
KEY_EQUALS = 0x2Bu,
KEY_LEFT_BRACE = 0x2Cu,
KEY_RIGHT_BRACE = 0x2Du,
KEY_BACKSLASH = 0x2Eu,
KEY_NON_US_HASH = 0x2Fu,
KEY_SEMICOLON = 0x30u,
KEY_APOSTROPHE = 0x31u,
KEY_GRAVE_ACCENT = 0x32u,
KEY_COMMA = 0x33u,
KEY_DOT = 0x34u,
KEY_SLASH = 0x35u,
KEY_CAPS_LOCK = 0x36u,
KEY_F1 = 0x37u,
KEY_F2 = 0x38u,
KEY_F3 = 0x39u,
KEY_F4 = 0x3Au,
KEY_F5 = 0x3Bu,
KEY_F6 = 0x3Cu,
KEY_F7 = 0x3Du,
KEY_F8 = 0x3Eu,
KEY_F9 = 0x3Fu,
KEY_F10 = 0x40u,
KEY_F11 = 0x41u,
KEY_F12 = 0x42u,
KEY_PRINT_SCREEN = 0x43u,
KEY_SCROLL_LOCK = 0x44u,
KEY_PAUSE = 0x45u,
KEY_INSERT = 0x46u,
KEY_HOME = 0x47u,
KEY_PAGE_UP = 0x48u,
KEY_DELETE = 0x49u,
KEY_END = 0x4Au,
KEY_PAGE_DOWN = 0x4Bu,
KEY_RIGHT = 0x4Cu,
KEY_LEFT = 0x4Du,
KEY_DOWN = 0x4Eu,
KEY_UP = 0x4Fu,
KEY_NUM_LOCK = 0x50u,
KEY_KEYPAD_SLASH = 0x51u,
KEY_KEYPAD_ASTERISK = 0x52u,
KEY_KEYPAD_MINUS = 0x53u,
KEY_KEYPAD_PLUS = 0x54u,
KEY_KEYPAD_ENTER = 0x55u,
KEY_KEYPAD_1 = 0x56u,
KEY_KEYPAD_2 = 0x57u,
KEY_KEYPAD_3 = 0x58u,
KEY_KEYPAD_4 = 0x59u,
KEY_KEYPAD_5 = 0x5Au,
KEY_KEYPAD_6 = 0x5Bu,
KEY_KEYPAD_7 = 0x5Cu,
KEY_KEYPAD_8 = 0x5Du,
KEY_KEYPAD_9 = 0x5Eu,
KEY_KEYPAD_0 = 0x5Fu,
KEY_KEYPAD_DOT = 0x60u,
KEY_NON_US_BACKSLASH = 0x61u,
KEY_KEYPAD_EQUALS = 0x62u,
KEY_MENU = 0x63u,
KEY_LEFT_CTRL = 0x64u,
KEY_LEFT_SHIFT = 0x65u,
KEY_LEFT_ALT = 0x66u,
KEY_LEFT_META = 0x67u,
KEY_RIGHT_CTRL = 0x68u,
KEY_RIGHT_SHIFT = 0x69u,
KEY_RIGHT_ALT = 0x6Au,
KEY_RIGHT_META = 0x6Bu,
KEY_MEDIA_MUTE = 0x6Cu,
KEY_MEDIA_VOLUME_INCREMENT = 0x6Du,
KEY_MEDIA_VOLUME_DECREMENT = 0x6Eu,
};
enum input_key_state {
INPUT_KEYSTATE_DOWN = 0x00u,
INPUT_KEYSTATE_UP = 0x01u,
};
enum input_button {
INPUT_BUTTON_MOUSE_LEFT = 0x00u,
INPUT_BUTTON_MOUSE_MIDDLE = 0x01u,
INPUT_BUTTON_MOUSE_RIGHT = 0x02u,
INPUT_BUTTON_MOUSE_BACK = 0x03u,
INPUT_BUTTON_MOUSE_FORWARD = 0x04u,
};
enum input_button_state {
INPUT_BUTTON_DOWN = 0x00u,
INPUT_BUTTON_UP = 0x01u,
};
struct input_event {
enum input_event_type ev_type;
union {
struct {
enum input_event_motion_type type;
int16_t movement_x;
int16_t movement_y;
} ev_motion;
struct {
enum input_button button;
enum input_button_state state;
} ev_button;
struct {
enum input_keycode key;
enum input_key_state state;
} ev_key;
};
};
struct input_event_hook {
void(*hook_callback)(struct device *, struct input_event *, enum input_event_hook_flags *, void *);
void *hook_arg;
struct queue_entry hook_head;
};
#endif
+99
View File
@@ -0,0 +1,99 @@
#ifndef MANGO_KEXT_H_
#define MANGO_KEXT_H_
#include <mango/status.h>
#include <mango/object.h>
#include <mango/compiler.h>
#include <mango/btree.h>
#define KERNEL_KEXT_ID "net.doorstuck.mango-kernel"
#define KEXT_IDENT_MAX 80
#define KEXT_NO_DEPENDENCIES NULL
#define __KEXT_INFO_VARNAME_2(a, b) a ## b
#define __KEXT_INFO_VARNAME_1(a, b) __KEXT_INFO_VARNAME_2(a, b)
#ifdef MANGO_INTERNAL
#define __KEXT_INFO_LINKAGE static
#define __KEXT_INFO_VARNAME() __KEXT_INFO_VARNAME_1(__kext_info, __LINE__)
#define __KEXT_INFO_DEPNAME() __KEXT_INFO_VARNAME_1(__kext_deps, __LINE__)
#define __KEXT_INFO_FLAGS KEXT_INTERNAL
#define __KEXT_INFO_ALIGNMENT 0x80
#else
#define __KEXT_INFO_LINKAGE
#define __KEXT_INFO_VARNAME() __kext_info
#define __KEXT_INFO_DEPNAME() __kext_deps
#define __KEXT_INFO_FLAGS KEXT_NONE
#define __KEXT_INFO_ALIGNMENT 0x80
#endif
#ifdef __cplusplus
#define DEFINE_KEXT(ident, online, offline, ...) \
static const char *__KEXT_INFO_DEPNAME()[] = { \
__VA_ARGS__, NULL \
}; \
static struct kext_info __section(".kextinfo") __aligned(__KEXT_INFO_ALIGNMENT) __used __KEXT_INFO_VARNAME() = { \
__KEXT_INFO_FLAGS, \
ident, \
online, \
offline, \
__KEXT_INFO_DEPNAME(), \
}
#else
#define DEFINE_KEXT(ident, online, offline, ...) \
static const char *__KEXT_INFO_DEPNAME()[] = { \
__VA_ARGS__, NULL \
}; \
static struct kext_info __section(".kextinfo") __aligned(__KEXT_INFO_ALIGNMENT) __used __KEXT_INFO_VARNAME() = { \
.k_flags = __KEXT_INFO_FLAGS, \
.k_ident = ident, \
.k_online = online, \
.k_offline = offline, \
.k_dependencies = __KEXT_INFO_DEPNAME(), \
}
#endif
struct kext;
enum kext_flags {
KEXT_NONE = 0x00u,
KEXT_INTERNAL = 0x01u,
KEXT_ONLINE = 0x02u,
};
struct kext_info {
enum kext_flags k_flags;
char k_ident[KEXT_IDENT_MAX];
kern_status_t(*k_online)(struct kext *);
kern_status_t(*k_offline)(struct kext *);
const char **k_dependencies;
};
struct kext {
struct object k_base;
enum kext_flags k_flags;
char k_ident[KEXT_IDENT_MAX];
uint64_t k_ident_hash;
struct btree_node k_node;
kern_status_t(*k_online)(struct kext *);
kern_status_t(*k_offline)(struct kext *);
unsigned int k_nr_dependencies;
struct kext **k_dependencies;
};
extern kern_status_t scan_internal_kexts(void);
extern kern_status_t bring_internal_kexts_online(void);
extern kern_status_t init_kernel_kext(void);
extern struct kext *kernel_kext(void);
extern kern_status_t kext_cache_init(void);
extern struct kext *kext_alloc(void);
extern void kext_release(struct kext *kext);
extern kern_status_t kext_register(struct kext *kext);
extern struct kext *kext_get_by_id(const char *ident);
extern kern_status_t kext_bring_online(struct kext *kext);
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef MANGO_LOCKS_H_
#define MANGO_LOCKS_H_
#include <mango/compiler.h>
#include <mango/machine/hwlock.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef __aligned(8) ml_hwlock_t spin_lock_t;
#define SPIN_LOCK_INIT ML_HWLOCK_INIT
#define spin_lock(lck) ml_hwlock_lock(lck);
#define spin_unlock(lck) ml_hwlock_unlock(lck);
#define spin_lock_irqsave(lck, flags) ml_hwlock_lock_irqsave(lck, flags);
#define spin_unlock_irqrestore(lck, flags) ml_hwlock_unlock_irqrestore(lck, flags);
#ifdef __cplusplus
}
#endif
#endif
+330
View File
@@ -0,0 +1,330 @@
/*
The Clear BSD License
Copyright (c) 2023 Max Wash
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted (subject to the limitations in the disclaimer
below) provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
*/
#ifndef MANGO_MEMBLOCK_H_
#define MANGO_MEMBLOCK_H_
#include <stddef.h>
#include <limits.h>
#include <mango/types.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MEMBLOCK_INIT_MEMORY_REGION_COUNT 128
#define MEMBLOCK_INIT_RESERVED_REGION_COUNT 128
#define __for_each_mem_range(i, type_a, type_b, p_start, p_end) \
for ((i)->__idx = 0, __next_memory_region(i, type_a, type_b, p_start, p_end); \
(i)->__idx != ULLONG_MAX; \
__next_memory_region(i, type_a, type_b, p_start, p_end))
/* iterate through all memory regions known to memblock.
this consists of all regions that have been registered
with memblock using memblock_add().
this iteration can be optionally constrained to a given region.
@param i the iterator. this should be a pointer of type struct memblock_iter.
for each iteration, this structure will be filled with details about
the current memory region.
@param p_start the lower bound of the memory region to iterate through.
if you don't want to use a lower bound, pass 0.
@param p_end the upper bound of the memory region to iterate through.
if you don't want to use an upper bound, pass UINTPTR_MAX.
EXAMPLE: to iterate through all memory regions (with no bounds):
struct memblock_iter it;
for_each_mem_region (&it, 0x0, UINTPTR_MAX) { ... }
EXAMPLE: to iterate through all memory regions between physical
addresses 0x40000 and 0x80000:
struct memblock_iter it;
for_each_mem_region (&it, 0x40000, 0x80000) { ... }
*/
#define for_each_mem_range(i, p_start, p_end) \
__for_each_mem_range(i, &memblock.memory, NULL, p_start, p_end)
/* iterate through all memory regions reserved using memblock.
this consists of all regions that have been registered
with memblock using memblock_reserve().
this iteration can be optionally constrained to a given region.
@param i the iterator. this should be a pointer of type struct memblock_iter.
for each iteration, this structure will be filled with details about
the current memory region.
@param p_start the lower bound of the memory region to iterate through.
if you don't want to use a lower bound, pass 0.
@param p_end the upper bound of the memory region to iterate through.
if you don't want to use an upper bound, pass UINTPTR_MAX.
EXAMPLE: to iterate through all reserved memory regions (with no bounds):
struct memblock_iter it;
for_each_reserved_mem_region (&it, 0x0, UINTPTR_MAX) { ... }
EXAMPLE: to iterate through all reserved memory regions between physical
addresses 0x40000 and 0x80000:
struct memblock_iter it;
for_each_reserved_mem_region (&it, 0x40000, 0x80000) { ... }
*/
#define for_each_reserved_mem_range(i, p_start, p_end) \
__for_each_mem_range(i, &memblock.reserved, NULL, p_start, p_end)
/* iterate through all memory regions known by memblock to be free.
this consists of all regions BETWEEN those regions that have been
registered using memblock_reserve(), bounded within the memory
regions added using memblock_add().
this iteration can be optionally constrained to a given region.
@param i the iterator. this should be a pointer of type struct memblock_iter.
for each iteration, this structure will be filled with details about
the current memory region.
@param p_start the lower bound of the memory region to iterate through.
if you don't want to use a lower bound, pass 0.
@param p_end the upper bound of the memory region to iterate through.
if you don't want to use an upper bound, pass UINTPTR_MAX.
EXAMPLE: if you have added the following memory regions to
memblock using memblock_add():
- 0x00000 -> 0x05fff
- 0x08000 -> 0x1ffff
...and you have reserved the following memory regions using
memblock_reserve():
- 0x01000 -> 0x04fff
- 0x09000 -> 0x0ffff
the following call:
struct memblock_iter it;
for_each_free_mem_range (&it, 0x0, UINTPTR_MAX) { ... }
would iterate through the following sequence of free memory ranges:
- 0x00000 -> 0x00fff
- 0x05000 -> 0x05fff
- 0x08000 -> 0x08fff
- 0x10000 -> 0x1ffff
*/
#define for_each_free_mem_range(i, p_start, p_end) \
__for_each_mem_range(i, &memblock.memory, &memblock.reserved, p_start, p_end)
typedef uint64_t memblock_index_t;
enum memblock_region_status {
/* Used in memblock.memory regions, indicates that the memory region exists */
MEMBLOCK_MEMORY = 0,
/* Used in memblock.reserved regions, indicates that the memory region was reserved
* by a call to memblock_alloc() */
MEMBLOCK_ALLOC,
/* Used in memblock.reserved regions, indicates that the memory region was reserved
* by a call to memblock_reserve() */
MEMBLOCK_RESERVED,
};
struct memblock_region {
/* the status of the memory region (free, reserved, allocated, etc) */
enum memblock_region_status status;
/* the address of the first byte that makes up the region */
phys_addr_t base;
/* the address of the last byte that makes up the region */
phys_addr_t limit;
};
/* buffer of memblock regions, all of which are the same type
(memory, reserved, etc) */
struct memblock_type {
struct memblock_region *regions;
unsigned int count;
unsigned int max;
const char *name;
};
struct memblock {
/* bounds of the memory region that can be used by memblock_alloc()
both of these are virtual addresses */
uintptr_t m_alloc_start, m_alloc_end;
/* memblock assumes that all memory in the alloc zone is contiguously mapped
(if paging is enabled). m_voffset is the offset that needs to be added to
a given physical address to get the corresponding virtual address */
uintptr_t m_voffset;
struct memblock_type memory;
struct memblock_type reserved;
};
struct memblock_iter {
memblock_index_t __idx;
phys_addr_t it_base;
phys_addr_t it_limit;
enum memblock_region_status it_status;
};
/* global memblock state. */
extern struct memblock memblock;
extern int __next_mem_range(struct memblock_iter *it);
/* initialise the global memblock state.
this function must be called before any other memblock functions can be used.
this function sets the bounds of the heap area. memory allocation requests
using memblock_alloc() will be constrained to this zone.
memblock assumes that all physical memory in the system is mapped to
an area in virtual memory, such that converting a physical address to
a valid virtual address can be done by simply applying an offset.
@param alloc_start the virtual address of the start of the heap area.
@param alloc_end the virtual address of the end of the heap area.
@param voffset the offset between the physical address of a given page and
its corresponding virtual address.
*/
extern int memblock_init(uintptr_t alloc_start, uintptr_t alloc_end, uintptr_t voffset);
/* add a region of memory to memblock.
this function is used to define regions of memory that are accessible, but
says nothing about the STATE of the given memory.
all memory is free by default. once a region of memory is added,
memblock_reserve() can be used to mark the memory as reserved.
@param base the physical address of the start of the memory region to add.
@oaram size the size of the memory region to add in bytes.
*/
extern int memblock_add(phys_addr_t base, size_t size);
/* mark a region of memory as reserved.
this function can only operate on regions of memory that have been previously
registered with memblock using memblock_add().
reserved memory will not be used by memblock_alloc(), and will remain
reserved when the vm_page memory map is initialised.
@param base the physical address of the start of the memory region to reserve.
@oaram size the size of the memory region to reserve in bytes.
*/
extern int memblock_reserve(phys_addr_t base, size_t size);
/* allocate a block of memory, returning a virtual address.
this function selects the first available region of memory that satisfies
the requested allocation size, marks `size` bytes of this region as reserved,
and returns the virtual address of the region.
when looking for a suitable region of memory, this function searches the
intersection of the following memory zones:
- the regions of memory added with memblock_alloc().
- the region of memory specified as the heap bounds during the call
to memblock_init().
and excludes the following regions:
- the regions of memory marked as reserved by memblock_reserve() and
previous calls to memblock_alloc()
@param size the size of the buffer to allocate in bytes.
@param align the alignment to use. for example, an alignment of 4096
will result in the returned pointer being a multiple
of 4096. this must be a power of 2.
*/
extern void *memblock_alloc(size_t size, phys_addr_t align);
/* allocate a block of memory, returning a physical address.
this function selects the first available region of memory that satisfies
the requested allocation size, marks `size` bytes of this region as reserved,
and returns the virtual address of the region.
when looking for a suitable region of memory, this function searches the
intersection of the following memory zones:
- the regions of memory added with memblock_alloc().
- the region of memory specified as the heap bounds during the call
to memblock_init().
and excludes the following regions:
- the regions of memory marked as reserved by memblock_reserve() and
previous calls to memblock_alloc()
@param size the size of the buffer to allocate in bytes.
@param align the alignment to use. for example, an alignment of 4096
will result in the returned pointer being a multiple
of 4096. this must be a power of 2.
*/
extern phys_addr_t memblock_alloc_phys(size_t size, phys_addr_t align);
/* free a block of memory using its virtual address.
due to limitations in memblock (as it is meant to be a simple,
early-boot allocator), you must specify the size of the memory
region you intend to free.
@param addr the virtual address of the region to free.
@param size the size of the region to free in bytes.
*/
extern int memblock_free(void *addr, size_t size);
/* free a block of memory using its physical address.
due to limitations in memblock (as it is meant to be a simple,
early-boot allocator), you must specify the size of the memory
region you intend to free.
@param addr the physical address of the region to free.
@param size the size of the region to free in bytes.
*/
extern int memblock_free_phys(phys_addr_t addr, size_t size);
/* convert a virtual pointer returned by memblock
to a physical address.
@param p the pointer to convert.
*/
extern phys_addr_t memblock_virt_to_phys(void *p);
/* convert a physical address returned by memblock
to a virtual pointer.
@param p the address to convert.
*/
extern void *memblock_phys_to_virt(phys_addr_t p);
extern void __next_memory_region(struct memblock_iter *it, \
struct memblock_type *type_a, struct memblock_type *type_b,
phys_addr_t start, phys_addr_t end);
#ifdef __cplusplus
}
#endif
#endif
+118
View File
@@ -0,0 +1,118 @@
#ifndef MANGO_OBJECT_H_
#define MANGO_OBJECT_H_
#include <mango/locks.h>
#include <mango/status.h>
#include <mango/flags.h>
#include <mango/vm.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OBJECT_MAGIC 0xBADDCAFE
#define OBJECT_NAME_MAX 64
#define OBJECT_PATH_MAX 256
#define OBJECT_CAST(to_type, to_type_member, p) \
((to_type *)((uintptr_t)p) - offsetof(to_type, to_type_member))
#define OBJECT_C_CAST(c_type, c_type_member, obj_type, objp) \
OBJECT_IS_TYPE(objp, obj_type) ? OBJECT_CAST(c_type, c_type_member, (objp)) : NULL
#define OBJECT_IS_TYPE(obj, type_ptr) \
((obj)->ob_type == (type_ptr))
struct object;
struct object_attrib;
enum object_type_flags {
OBJTYPE_INIT = 0x01u,
};
struct object_ops {
kern_status_t(*open)(struct object *obj);
kern_status_t(*close)(struct object *obj);
kern_status_t(*read)(struct object *obj, void *p, size_t off, size_t *r, mango_flags_t flags);
kern_status_t(*write)(struct object *obj, const void *p, size_t off, size_t *w, mango_flags_t flags);
kern_status_t(*destroy)(struct object *obj);
kern_status_t(*query_name)(struct object *obj, char out[OBJECT_NAME_MAX]);
kern_status_t(*parse)(struct object *obj, const char *path, struct object **out);
kern_status_t(*get_named)(struct object *obj, const char *name, struct object **out);
kern_status_t(*get_at)(struct object *obj, size_t at, struct object **out);
kern_status_t(*read_attrib)(struct object *obj, struct object_attrib *attrib, char *out, size_t max, size_t *r);
kern_status_t(*write_attrib)(struct object *obj, struct object_attrib *attrib, const char *s, size_t len, size_t *r);
};
struct object_attrib {
char *a_name;
struct queue_entry a_list;
};
struct object_type {
enum object_type_flags ob_flags;
char ob_name[32];
unsigned int ob_size;
unsigned int ob_header_offset;
struct vm_cache ob_cache;
struct queue_entry ob_list;
struct queue ob_attrib;
struct object_ops ob_ops;
};
struct object {
uint32_t ob_magic;
struct object_type *ob_type;
spin_lock_t ob_lock;
unsigned int ob_refcount;
unsigned int ob_handles;
struct queue ob_attrib;
struct queue_entry ob_list;
} __aligned(sizeof(long));
extern kern_status_t object_bootstrap(void);
extern kern_status_t object_type_register(struct object_type *p);
extern kern_status_t object_type_unregister(struct object_type *p);
extern struct object_namespace *global_namespace(void);
extern struct object_namespace *object_namespace_create(void);
extern struct object *ns_header(struct object_namespace *ns);
extern kern_status_t object_namespace_get_object(struct object_namespace *ns, const char *path, struct object **out);
extern kern_status_t object_namespace_create_link(struct object_namespace *ns, const char *linkpath, struct object *dest);
extern kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj);
extern kern_status_t object_unpublish(struct object_namespace *ns, struct object *obj);
extern struct object *object_create(struct object_type *type);
extern struct object *object_ref(struct object *obj);
extern void object_deref(struct object *obj);
extern void object_lock(struct object *obj);
extern void object_unlock(struct object *obj);
extern void object_lock_irqsave(struct object *obj, unsigned long *flags);
extern void object_unlock_irqrestore(struct object *obj, unsigned long flags);
static inline kern_status_t object_get(const char *path, struct object **out)
{
return object_namespace_get_object(global_namespace(), path, out);
}
extern kern_status_t object_read(struct object *obj, void *p, size_t offset, size_t max, size_t *nr_read, mango_flags_t flags);
extern kern_status_t object_write(struct object *obj, const void *p, size_t offset, size_t max, size_t *nr_written, mango_flags_t flags);
extern kern_status_t object_get_child_named(struct object *obj, const char *name, struct object **out);
extern kern_status_t object_get_child_at(struct object *obj, size_t at, struct object **out);
extern kern_status_t object_query_name(struct object *obj, char name[OBJECT_NAME_MAX]);
extern struct object *set_create(const char *name);
extern kern_status_t set_add_object(struct object *set, struct object *obj);
extern kern_status_t set_remove_object(struct object *set, struct object *obj);
extern bool object_is_set(struct object *obj);
extern struct object *link_create(const char *name, struct object *dest);
extern struct object *link_read_ptr(struct object *link);
extern bool object_is_link(struct object *obj);
extern void init_set_objects(void);
extern void init_link_objects(void);
extern void init_global_namespace(void);
#ifdef __cplusplus
}
#endif
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef MANGO_PANIC_H_
#define MANGO_PANIC_H_
#include <mango/compiler.h>
struct cpu_context;
#define panic(...) panic_irq(NULL, __VA_ARGS__)
extern void __noreturn panic_irq(struct cpu_context *ctx, const char *fmt, ...);
#endif
+36
View File
@@ -0,0 +1,36 @@
#ifndef MANGO_PERCPU_H_
#define MANGO_PERCPU_H_
#include <mango/status.h>
#include <mango/compiler.h>
#include <mango/sched.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DEFINE_PERCPU_VAR(type, name) \
__section(".data.percpu") type name
#define percpu_get(var) \
__extension__({ \
preempt_disable(); \
__percpu_get(this_cpu(), var); \
})
#define percpu_get_from(cpu, var) \
__extension__({ \
preempt_disable(); \
__percpu_get(cpu, var); \
})
#define percpu_put(var) preempt_enable();
extern kern_status_t init_per_cpu_areas(void);
extern void *__percpu_get(unsigned int cpu, void *var);
#ifdef __cplusplus
}
#endif
#endif
+42
View File
@@ -0,0 +1,42 @@
#ifndef MANGO_PMAP_H_
#define MANGO_PMAP_H_
/* all the functions declared in this file are defined in arch/xyz/pmap.c */
#include <mango/vm.h>
#include <mango/status.h>
#include <mango/machine/pmap.h>
#include <stddef.h>
#define PFN(x) ((x) >> VM_PAGE_SHIFT)
#ifdef __cplusplus
extern "C" {
#endif
typedef ml_pmap_t pmap_t;
typedef ml_pfn_t pfn_t;
enum pmap_flags {
PMAP_NORMAL = 0x00u,
PMAP_HUGEPAGE = 0x01u,
};
extern void pmap_bootstrap(void);
extern pmap_t get_kernel_pmap(void);
extern pmap_t pmap_create(void);
extern void pmap_destroy(pmap_t pmap);
extern void pmap_switch(pmap_t pmap);
extern kern_status_t pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot prot, enum pmap_flags flags);
extern kern_status_t pmap_add_block(pmap_t pmap, void *p, pfn_t pfn, size_t len, enum vm_prot prot, enum pmap_flags flags);
extern kern_status_t pmap_remove(pmap_t pmap, void *p);
extern kern_status_t pmap_remove_range(pmap_t pmap, void *p, size_t len);
#ifdef __cplusplus
}
#endif
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef MANGO_PRINTK_H_
#define MANGO_PRINTK_H_
#include <mango/console.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void early_printk_init(struct console *con);
extern int printk(const char *format, ...);
#ifdef __cplusplus
}
#endif
#endif
+62
View File
@@ -0,0 +1,62 @@
#ifndef MANGO_QUEUE_H_
#define MANGO_QUEUE_H_
#include <mango/libc/string.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define QUEUE_CONTAINER(t, m, v) ((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0))
#define QUEUE_INIT ((struct queue){ .q_first = NULL, .q_last = NULL })
#define QUEUE_ENTRY_INIT ((struct queue_entry){ .qe_next = NULL, .qe_prev = NULL })
#define queue_foreach(iter_type, iter_name, queue_name, node_member) \
for (iter_type *iter_name = (iter_type *)QUEUE_CONTAINER(iter_type, node_member, queue_first(queue_name)); \
iter_name; \
iter_name = (iter_type *)QUEUE_CONTAINER(iter_type, node_member, queue_next(&((iter_name)->node_member))))
#define queue_foreach_r(iter_type, iter_name, queue_name, node_member) \
for (iter_type *iter_name = (iter_type *)QUEUE_CONTAINER(iter_type, node_member, queue_last(queue_name)); \
iter_name; \
iter_name = (iter_type *)QUEUE_CONTAINER(iter_type, node_member, queue_prev(&((iter_name)->node_member))))
struct queue_entry {
struct queue_entry *qe_next;
struct queue_entry *qe_prev;
};
struct queue {
struct queue_entry *q_first;
struct queue_entry *q_last;
};
static inline void queue_init(struct queue *q) { memset(q, 0x00, sizeof *q); }
static inline bool queue_empty(struct queue *q) { return q->q_first == NULL; }
static inline struct queue_entry *queue_first(struct queue *q) { return q->q_first; }
static inline struct queue_entry *queue_last(struct queue *q) { return q->q_last; }
static inline struct queue_entry *queue_next(struct queue_entry *entry) { return entry->qe_next; }
static inline struct queue_entry *queue_prev(struct queue_entry *entry) { return entry->qe_prev; }
extern size_t queue_length(struct queue *q);
extern void queue_insert_before(struct queue *q, struct queue_entry *entry, struct queue_entry *before);
extern void queue_insert_after(struct queue *q, struct queue_entry *entry, struct queue_entry *after);
extern void queue_push_front(struct queue *q, struct queue_entry *entry);
extern void queue_push_back(struct queue *q, struct queue_entry *entry);
extern struct queue_entry *queue_pop_front(struct queue *q);
extern struct queue_entry *queue_pop_back(struct queue *q);
extern void queue_delete(struct queue *q, struct queue_entry *entry);
extern void queue_delete_all(struct queue *q);
#ifdef __cplusplus
}
#endif
#endif
+34
View File
@@ -0,0 +1,34 @@
#ifndef MANGO_RINGBUFFER_H_
#define MANGO_RINGBUFFER_H_
#include <mango/locks.h>
#include <mango/sched.h>
struct ringbuffer {
unsigned char *r_buffer;
size_t r_write_ptr;
size_t r_read_ptr;
size_t r_size;
spin_lock_t r_lock;
struct waitqueue r_wait_readers;
struct waitqueue r_wait_writers;
};
extern struct ringbuffer *ringbuffer_create(size_t size);
extern void ringbuffer_destroy(struct ringbuffer *buf);
extern kern_status_t ringbuffer_init(struct ringbuffer *buf, size_t size);
extern kern_status_t ringbuffer_deinit(struct ringbuffer *buf);
extern size_t ringbuffer_unread(struct ringbuffer *buf);
extern size_t ringbuffer_avail(struct ringbuffer *buf);
extern size_t ringbuffer_read(struct ringbuffer *buf, size_t size, void *buffer, mango_flags_t flags);
extern size_t ringbuffer_write(struct ringbuffer *buf, size_t size, const void *buffer, mango_flags_t flags);
/* TODO */
//extern size_t ringbuffer_peek(struct ringbuffer *buf, size_t at, size_t size, void *buffer);
//extern size_t ringbuffer_skip(struct ringbuffer *buf, size_t count);
extern int ringbuffer_write_would_block(struct ringbuffer *buf);
#endif
+246
View File
@@ -0,0 +1,246 @@
#ifndef MANGO_SCHED_H_
#define MANGO_SCHED_H_
#include <mango/btree.h>
#include <mango/locks.h>
#include <mango/object.h>
#include <mango/pmap.h>
#include <mango/queue.h>
#include <mango/status.h>
#define TASK_NAME_MAX 64
#define PRIO_MAX 32
#define THREAD_KSTACK_ORDER VM_PAGE_4K
#define THREAD_MAX 65536
#define wait_event(wq, cond) \
({ \
struct thread *self = current_thread(); \
struct wait_item waiter; \
wait_item_init(&waiter, self); \
for (;;) { \
thread_wait_begin(&waiter, wq); \
if (cond) { \
break; \
} \
schedule(SCHED_NORMAL); \
} \
thread_wait_end(&waiter, wq); \
})
#ifdef __cplusplus
extern "C" {
#endif
struct runqueue;
struct work_item;
enum task_state {
TASK_RUNNING,
TASK_STOPPED,
};
enum thread_state {
THREAD_READY = 1,
THREAD_SLEEPING = 2,
THREAD_STOPPED = 3,
};
enum thread_flags {
THREAD_F_NEED_RESCHED = 0x01u,
THREAD_F_NO_PREEMPT = 0x02u,
};
enum sched_priority {
PRIO_IDLE = 4,
PRIO_SUBNORMAL = 6,
PRIO_NORMAL = 10,
PRIO_SUPERNORMAL = 14,
PRIO_HIGH = 18,
PRIO_REALTIME = 24,
};
enum sched_mode {
/* used when calling from non-interrupt context.
threads that aren't in state THREAD_READY are
removed from the runqueue. */
SCHED_NORMAL = 0,
/* used when calling from interrupt context.
threads that aren't in state THREAD_READY are
still added to the runqueue. */
SCHED_IRQ = 1,
};
struct task {
struct object t_base;
struct task *t_parent;
unsigned int t_id;
enum task_state t_state;
char t_name[TASK_NAME_MAX];
pmap_t t_pmap;
struct btree_node t_tasklist;
struct queue t_threads;
struct queue t_children;
};
struct thread {
struct object thr_base;
enum thread_state tr_state;
enum thread_flags tr_flags;
struct task *tr_parent;
unsigned int tr_id;
unsigned int tr_prio;
cycles_t tr_charge_period_start;
cycles_t tr_quantum_cycles, tr_quantum_target;
cycles_t tr_total_cycles;
uintptr_t tr_sp, tr_bp;
struct runqueue *tr_rq;
struct queue_entry tr_threads;
struct queue_entry tr_rqentry;
struct vm_page *tr_kstack;
};
struct runqueue {
struct queue rq_queues[PRIO_MAX];
uint32_t rq_readybits;
spin_lock_t rq_lock;
unsigned int rq_nthreads;
struct thread *rq_cur, *rq_idle;
};
struct timer {
struct queue_entry t_entry;
struct cpu_data *t_cpu;
struct thread *t_owner;
unsigned long t_expiry;
void (*t_callback)(struct timer *);
};
struct wait_item {
struct thread *w_thread;
struct queue_entry w_entry;
};
struct waitqueue {
struct queue wq_waiters;
spin_lock_t wq_lock;
};
typedef void (*work_func_t)(struct work_item *);
struct work_item {
void *w_data;
work_func_t w_func;
struct queue_entry w_head;
};
struct worker_pool {
struct thread **wp_workers;
size_t wp_nworkers;
};
struct workqueue {
spin_lock_t wq_lock;
struct queue wq_queue; /* list of struct work_item */
};
extern kern_status_t sched_init(void);
extern void schedule(enum sched_mode mode);
extern void preempt_disable(void);
extern void preempt_enable(void);
extern void rq_init(struct runqueue *rq);
extern struct thread *rq_dequeue(struct runqueue *rq);
extern void rq_enqueue(struct runqueue *rq, struct thread *thr);
static inline void rq_lock(struct runqueue *rq, unsigned long *flags)
{
spin_lock_irqsave(&rq->rq_lock, flags);
}
static inline void rq_unlock(struct runqueue *rq, unsigned long flags)
{
spin_unlock_irqrestore(&rq->rq_lock, flags);
}
extern void rq_remove_thread(struct runqueue *rq, struct thread *thr);
extern struct runqueue *cpu_rq(unsigned int cpu);
extern struct task *task_alloc(void);
static inline struct task *task_ref(struct task *task)
{
return OBJECT_CAST(struct task, t_base, object_ref(&task->t_base));
}
static inline void task_deref(struct task *task)
{
object_deref(&task->t_base);
}
extern struct task *task_from_pid(unsigned int pid);
extern struct task *kernel_task(void);
extern struct task *idle_task(void);
extern cycles_t default_quantum(void);
extern bool need_resched(void);
extern struct task *current_task(void);
extern struct thread *current_thread(void);
extern struct runqueue *select_rq_for_thread(struct thread *thr);
extern void schedule_thread_on_cpu(struct thread *thr);
extern void start_charge_period(void);
extern void end_charge_period(void);
static inline void task_lock_irqsave(struct task *task, unsigned long *flags)
{
object_lock_irqsave(&task->t_base, flags);
}
static inline void task_unlock_irqrestore(
struct task *task,
unsigned long flags)
{
object_unlock_irqrestore(&task->t_base, flags);
}
extern struct thread *thread_alloc(void);
extern kern_status_t thread_init(struct thread *thr, uintptr_t ip);
extern int thread_priority(struct thread *thr);
extern void idle(void);
extern struct thread *create_kernel_thread(void (*fn)(void));
extern struct thread *create_idle_thread(void);
extern void add_timer(struct timer *timer);
extern void remove_timer(struct timer *timer);
extern unsigned long schedule_timeout(unsigned long clock_ticks);
extern unsigned long milli_sleep(unsigned long ms);
extern void sleep_forever(void);
extern void wait_item_init(struct wait_item *item, struct thread *thr);
extern void thread_wait_begin(struct wait_item *waiter, struct waitqueue *q);
extern void thread_wait_end(struct wait_item *waiter, struct waitqueue *q);
extern void wait_on_queue(struct waitqueue *q);
extern void wakeup_queue(struct waitqueue *q);
extern void wakeup_one(struct waitqueue *q);
extern void work_item_init(work_func_t func, void *data, struct work_item *out);
extern void workqueue_init(struct workqueue *wq);
extern struct worker_pool *worker_pool_create(size_t nworkers);
extern struct worker_pool *global_worker_pool(void);
extern bool schedule_work_on(struct workqueue *wq, struct work_item *work);
extern bool schedule_work(struct work_item *work);
extern void wake_workers(struct workqueue *wq, struct worker_pool *pool);
#ifdef __cplusplus
}
#endif
#endif
+21
View File
@@ -0,0 +1,21 @@
#ifndef MANGO_STATUS_H_
#define MANGO_STATUS_H_
typedef unsigned int kern_status_t;
#define KERN_OK (0)
#define KERN_UNIMPLEMENTED (1)
#define KERN_NAME_EXISTS (2)
#define KERN_INVALID_ARGUMENT (3)
#define KERN_UNSUPPORTED (4)
#define KERN_NO_MEMORY (5)
#define KERN_NO_ENTRY (6)
#define KERN_WOULD_BLOCK (7)
#define KERN_BUSY (8)
#define KERN_NO_DEVICE (9)
#define KERN_DEVICE_STUCK (10)
#define KERN_IO_ERROR (11)
extern const char *kern_status_string(kern_status_t status);
#endif
+113
View File
@@ -0,0 +1,113 @@
#ifndef MANGO_TERMIOS_H_
#define MANGO_TERMIOS_H_
#include <stdint.h>
#define NCCS 32
#define BRKINT 00000001
#define ICRNL 00000002
#define IGNBRK 00000004
#define IGNCR 00000010
#define IGNPAR 00000020
#define INLCR 00000040
#define INPCK 00000100
#define ISTRIP 00000200
#define IUCLC 00000400
#define IXANY 00001000
#define IXOFF 00002000
#define IXON 00004000
#define PARMRK 00010000
#define OPOST 00000001
#define OLCUC 00000002
#define ONLCR 00000004
#define OCRNL 00000010
#define ONOCR 00000020
#define ONLRET 00000040
#define NLDLY 00000100
#define NL0 00000000
#define NL1 00000100
#define OFILL 00000200
#define CRDLY 00003400
#define CR0 00000000
#define CR1 00000400
#define CR2 00001000
#define CR3 00002000
#define TABDLY 00034000
#define TAB0 00000000
#define TAB1 00004000
#define TAB2 00010000
#define TAB3 00020000
#define BSDLY 00040000
#define BS0 00000000
#define BS1 00040000
#define VTDLY 00100000
#define VT0 00000000
#define VT1 00100000
#define FFDLY 00200000
#define FF0 00000000
#define FF1 00200000
#define B0 0
#define B50 50
#define B75 75
#define B110 110
#define B134 134
#define B150 150
#define B200 200
#define B300 300
#define B600 600
#define B1200 1200
#define B1800 1800
#define B2400 2400
#define B4800 4800
#define B9600 9600
#define B19200 19200
#define B38400 38400
#define CSIZE 00000007
#define CS5 00000000
#define CS6 00000001
#define CS7 00000002
#define CS8 00000004
#define CSTOPB 00000010
#define CREAD 00000020
#define PARENB 00000040
#define PARODD 00000100
#define HUPCL 00000200
#define CLOCAL 00000400
#define ECHO 00000001
#define ECHOE 00000002
#define ECHOK 00000004
#define ECHONL 00000010
#define ICANON 00000020
#define IEXTEN 00000040
#define ISIG 00000100
#define NOFLSH 00000200
#define TOSTOP 00000400
#define XCASE 00001000
#define TCSANOW 1
#define TCSADRAIN 2
#define TCSAFLUSH 3
#define TCIFLUSH 1
#define TCOFLUSH 2
#define TCIOFLUSH (TCIFLUSH | TCOFLUSH)
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
typedef unsigned char cc_t;
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[NCCS];
};
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef MANGO_TEST_H_
#define MANGO_TEST_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int run_all_tests(void);
#ifdef __cplusplus
}
#endif
#endif
+145
View File
@@ -0,0 +1,145 @@
#ifndef MANGO_TTY_H_
#define MANGO_TTY_H_
#include <mango/status.h>
#include <mango/device.h>
#include <mango/queue.h>
#include <mango/object.h>
#include <mango/termios.h>
#include <stdint.h>
#define TTY_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? (dev)->chr.c_tty : NULL)
#define TTY_DRIVER(drv) ((struct tty_driver *)((char *)drv - offsetof(struct tty_driver, tty_base)))
#define TTY_INPUT_QUEUE_SIZE 256
#define TTY_LINE_MAX 4096
struct kext;
/* The TTY system.
TTYs are an enhanced version of the console object. Rather than a simple output
device for log messages, TTYs are intended to support fully-featured interactive
user sessions, including advanced display manipulation (if applicable) and
buffered user input.
A TTY object is split into 2 parts:
- struct tty: This represents the terminal session, and tracks things like the cursor
position, input buffer, flags, etc.
- struct tty_driver: This is a set of function callbacks that the TTY can use to
manipulate the output device. This could represent a char-based framebuffer
device, a serial port, etc.
*/
#ifdef __cplusplus
extern "C" {
#endif
enum tty_driver_type {
/* For TTYs operating on simple IO devices like serial ports.
Allows writing characters, receiving characters, and not much else. */
TTY_DRIVER_SIMPLE,
/* For TTYs operating on more capable display interfaces.
Allows putting characters at arbitrary locations, scrolling, etc */
TTY_DRIVER_FULL,
};
/* TTY cursor status. The extra cursor styles are just for completeness,
the important one to support (if possible), is TTY_CURSOR_NONE.
The others can be interpreted as "just turn on a cursor of any style". */
enum tty_cursor {
TTY_CURSOR_ULINE,
TTY_CURSOR_BLOCK,
TTY_CURSOR_NONE,
};
/* direction to use for scrolling. The important one to support is
TTY_SCROLL_DOWN for when output overflows the display */
enum tty_scroll_dir {
TTY_SCROLL_DOWN,
TTY_SCROLL_UP,
};
enum tty_modifier_key {
TTY_KEY_OTHER = 0x00u,
TTY_KEY_CTRL = 0x01u,
TTY_KEY_ALT = 0x02u,
TTY_KEY_SHIFT = 0x04u,
};
/* character attribute. this could be as simple as VGA's 16-colour palette
plus an extra bit for bright, or a full 24-bit RGB value with bold and underline
support, depending on what the driver supports. */
typedef uint64_t tty_attrib_t;
struct tty_driver_ops {
void (*tty_init)(struct device *dev);
void (*tty_deinit)(struct device *dev);
void (*tty_clear)(struct device *dev, int x, int y, int width, int height);
void (*tty_putc)(struct device *dev, int c, int xpos, int ypos, tty_attrib_t attrib);
void (*tty_set_cursor)(struct device *dev, enum tty_cursor cur);
void (*tty_move_cursor)(struct device *dev, int x, int y);
void (*tty_scroll)(struct device *dev, enum tty_scroll_dir dir, int lines);
};
struct tty_driver {
struct driver tty_base;
char tty_name[16];
enum tty_driver_type tty_type;
struct queue_entry tty_head;
struct tty_driver_ops *tty_ops;
};
struct tty_ldisc {
char name[OBJECT_NAME_MAX];
kern_status_t(*read)(struct device *, void *, size_t, size_t *, mango_flags_t);
void(*write)(struct device *, const struct input_event *);
};
struct tty_device {
unsigned int tty_xcells, tty_ycells;
unsigned int tty_xcur, tty_ycur;
struct termios tty_config;
tty_attrib_t tty_curattrib;
enum tty_modifier_key tty_modstate;
struct tty_ldisc *tty_ldisc;
/* input characters processed from tty_events, returned by tty_read() */
struct ringbuffer tty_input;
char *tty_linebuf;
};
extern void register_tty_console(void);
extern void redirect_printk_to_tty(struct device *dest);
extern kern_status_t tty_bootstrap(void);
extern struct tty_ldisc *tty_default_line_discipline(void);
extern struct device *tty_device_create(void);
extern kern_status_t tty_device_register(struct device *dev, struct tty_driver *owner, struct device *parent);
extern void tty_set_foreground(struct device *tty);
extern kern_status_t tty_connect_foreground_input_device(struct device *input);
extern struct tty_driver *tty_driver_create(struct kext *self, const char *name);
extern kern_status_t tty_driver_destroy(struct tty_driver *drv);
extern kern_status_t tty_driver_register(struct tty_driver *drv);
extern kern_status_t tty_driver_unregister(struct tty_driver *drv);
static inline struct driver *tty_driver_base(struct tty_driver *drv)
{
return &drv->tty_base;
}
extern kern_status_t tty_read(struct device *tty, void *buf, size_t offset, size_t max, size_t *nr_read, mango_flags_t flags);
extern kern_status_t tty_write(struct device *tty, const void *buf, size_t offset, size_t len, size_t *nr_written, mango_flags_t flags);
extern kern_status_t tty_report_event(struct device *tty, const struct input_event *ev);
#ifdef __cplusplus
}
#endif
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef MANGO_TYPES_H_
#define MANGO_TYPES_H_
#include <stdint.h>
#define CYCLES_MAX UINT64_MAX
typedef uintptr_t phys_addr_t;
typedef uint64_t cycles_t;
typedef uint64_t sectors_t;
typedef unsigned int umode_t;
#endif
+60
View File
@@ -0,0 +1,60 @@
#ifndef MANGO_UTIL_H_
#define MANGO_UTIL_H_
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define CLAMP(x, lo, hi) (MIN(MAX(x, lo), hi))
extern uint64_t hash_string(const char *s);
extern void data_size_to_string(size_t value, char *out, size_t outsz);
static inline bool power_of_2(size_t x) { return (x > 0 && (x & (x - 1)) == 0); }
static inline unsigned long long div64_pow2(unsigned long long x, unsigned long long y)
{
return x >> (__builtin_ctz(y));
}
static inline unsigned long long absdiff64(unsigned long long x, unsigned long long y)
{
return x < y ? y - x : x - y;
}
extern int16_t host_to_big_i16(int16_t v);
extern int16_t host_to_little_i16(int16_t v);
extern int16_t big_to_host_i16(int16_t v);
extern int16_t little_to_host_i16(int16_t v);
extern uint16_t host_to_big_u16(uint16_t v);
extern uint16_t host_to_little_u16(uint16_t v);
extern uint16_t big_to_host_u16(uint16_t v);
extern uint16_t little_to_host_u16(uint16_t v);
extern int32_t host_to_big_i32(int32_t v);
extern int32_t host_to_little_i32(int32_t v);
extern int32_t big_to_host_i32(int32_t v);
extern int32_t little_to_host_i32(int32_t v);
extern uint32_t host_to_big_u32(uint32_t v);
extern uint32_t host_to_little_u32(uint32_t v);
extern uint32_t big_to_host_u32(uint32_t v);
extern uint32_t little_to_host_u32(uint32_t v);
extern int64_t host_to_big_i64(int64_t v);
extern int64_t host_to_little_i64(int64_t v);
extern int64_t big_to_host_i64(int64_t v);
extern int64_t little_to_host_i64(int64_t v);
extern uint64_t host_to_big_u64(uint64_t v);
extern uint64_t host_to_little_u64(uint64_t v);
extern uint64_t big_to_host_u64(uint64_t v);
extern uint64_t little_to_host_u64(uint64_t v);
#ifdef __cplusplus
}
#endif
#endif
+346
View File
@@ -0,0 +1,346 @@
#ifndef MANGO_VM_H_
#define MANGO_VM_H_
#include <stddef.h>
#include <mango/types.h>
#include <mango/status.h>
#include <mango/queue.h>
#include <mango/btree.h>
#include <mango/bitmap.h>
#include <mango/locks.h>
#include <mango/machine/vm.h>
#ifdef __cplusplus
extern "C" {
#endif
struct bcache;
/* maximum number of NUMA nodes */
#define VM_MAX_NODES 64
/* maximum number of memory zones per node */
#define VM_MAX_ZONES (VM_ZONE_MAX + 1)
/* maximum number of supported page orders */
#define VM_MAX_PAGE_ORDERS (VM_PAGE_MAX_ORDER + 1)
/* maximum number of sparse memory sectors */
#define VM_MAX_SECTORS 8192
/* maximum number of disk sectors that can be stored in a single
page. AKA the number of bits in the sector bitmap.
used by the block cache */
#define VM_MAX_SECTORS_PER_PAGE 32
#define VM_CHECK_ALIGN(p, mask) ((((p) & (mask)) == (p)) ? 1 : 0)
#define VM_CACHE_INITIALISED(c) ((c)->c_obj_count != 0)
#define VM_PAGE_IS_FREE(pg) (((pg)->p_flags & (VM_PAGE_RESERVED | VM_PAGE_ALLOC)) == 0)
#define vm_page_foreach(pg, i) \
for (struct vm_page *i = (pg); i; i = vm_page_get_next_tail(i))
typedef phys_addr_t vm_alignment_t;
typedef unsigned int vm_node_id_t;
struct vm_object {
unsigned int reserved;
};
enum vm_model {
VM_MODEL_FLAT = 1,
VM_MODEL_SPARSE,
};
enum vm_prot {
VM_PROT_READ = 0x01u,
VM_PROT_WRITE = 0x02u,
VM_PROT_EXEC = 0x04u,
VM_PROT_USER = 0x08u,
VM_PROT_SVR = 0x10u,
VM_PROT_NOCACHE = 0x20u,
};
enum vm_flags {
VM_NORMAL = 0x00u,
VM_GET_DMA = 0x01u,
};
enum vm_zone_id {
/* NOTE that these are used as indices into the node_zones array in vm/zone.c
they need to be continuous, and must start at 0!
not all of these zones are implemented for every architecture. */
VM_ZONE_DMA = 0u,
VM_ZONE_NORMAL = 1u,
VM_ZONE_HIGHMEM = 2u,
};
enum vm_page_order {
VM_PAGE_4K = 0u,
VM_PAGE_8K,
VM_PAGE_16K,
VM_PAGE_32K,
VM_PAGE_64K,
VM_PAGE_128K,
VM_PAGE_256K,
VM_PAGE_512K,
VM_PAGE_1M,
VM_PAGE_2M,
VM_PAGE_4M,
VM_PAGE_8M,
VM_PAGE_16M,
VM_PAGE_32M,
VM_PAGE_64M,
VM_PAGE_128M,
/* struct vm_page only has 4 bits to store the page order with.
the maximum order that can be stored in 4 bits is 15 (VM_PAGE_128M)
to use any of the page orders listed here, this field
will have to be expanded. */
VM_PAGE_256M,
VM_PAGE_512M,
VM_PAGE_1G,
VM_PAGE_2G,
VM_PAGE_4G,
VM_PAGE_8G,
VM_PAGE_16G,
VM_PAGE_32G,
VM_PAGE_64G,
};
enum vm_page_flags {
/* page is reserved (probably by a call to memblock_reserve()) and cannot be
returned by any allocation function */
VM_PAGE_RESERVED = 0x01u,
/* page has been allocated by a zone's buddy allocator, and is in-use */
VM_PAGE_ALLOC = 0x02u,
/* page is the first page of a huge-page */
VM_PAGE_HEAD = 0x04u,
/* page is part of a huge-page */
VM_PAGE_HUGE = 0x08u,
/* page is holding cached data from secondary storage, and can be freed if necessary (and not dirty). */
VM_PAGE_CACHE = 0x10u,
};
enum vm_memory_region_status {
VM_REGION_FREE = 0x01u,
VM_REGION_RESERVED = 0x02u,
};
enum vm_cache_flags {
VM_CACHE_OFFSLAB = 0x01u,
VM_CACHE_DMA = 0x02u
};
struct vm_zone_descriptor {
enum vm_zone_id zd_id;
vm_node_id_t zd_node;
const char zd_name[32];
phys_addr_t zd_base;
phys_addr_t zd_limit;
};
struct vm_zone {
struct vm_zone_descriptor z_info;
spin_lock_t z_lock;
struct queue z_free_pages[VM_MAX_PAGE_ORDERS];
unsigned long z_size;
};
struct vm_pg_data {
struct vm_zone pg_zones[VM_MAX_ZONES];
};
struct vm_region {
enum vm_memory_region_status r_status;
phys_addr_t r_base;
phys_addr_t r_limit;
};
struct vm_cache {
const char *c_name;
enum vm_cache_flags c_flags;
struct queue_entry c_list;
struct queue c_slabs_full;
struct queue c_slabs_partial;
struct queue c_slabs_empty;
spin_lock_t c_lock;
/* number of objects that can be stored in a single slab */
unsigned int c_obj_count;
/* the size of object kept in the cache */
unsigned int c_obj_size;
/* combined size of struct vm_slab and the freelist */
unsigned int c_hdr_size;
/* power of 2 alignment for objects returned from the cache */
unsigned int c_align;
/* offset from one object to the next in a slab.
this may be different from c_obj_size depending
on the alignment settings for this cache. */
unsigned int c_stride;
/* size of page used for slabs */
unsigned int c_page_order;
};
struct vm_slab {
struct vm_cache *s_cache;
/* queue entry for struct vm_cache.c_slabs_* */
struct queue_entry s_list;
/* pointer to the first object slot. */
void *s_objects;
/* the number of objects allocated on the slab. */
unsigned int s_obj_allocated;
/* the index of the next free object.
if s_free is equal to FREELIST_END (defined in vm/cache.c)
there are no free slots left in the slab. */
unsigned int s_free;
/* list of free object slots.
when allocating:
- s_free should be set to the value of s_freelist[s_free]
when freeing:
- s_free should be set to the index of the object being freed.
- s_freelist[s_free] should be set to the previous value of s_free.
this is commented as it as flexible arrays are not supported in c++.
*/
//unsigned int s_freelist[];
};
struct vm_page {
/* order of the page block that this page belongs too */
uint32_t p_order : 4;
/* the id of the NUMA node that this page belongs to */
uint32_t p_node : 6;
/* the id of the memory zone that this page belongs to */
uint32_t p_zone : 3;
/* vm_page_flags_t bitfields. */
uint32_t p_sector : 11;
/* some unused bits */
uint32_t p_reserved : 8;
uint32_t p_flags;
/* owner-specific pointer */
union {
struct vm_slab *p_slab;
struct bcache *p_bcache;
void *p_priv0;
};
/* multi-purpose list/tree entry.
the owner of the page can decide what to do with this.
some examples:
- the buddy allocator uses this to maintain its per-zone free-page lists.
- the block cache uses this to maintain a tree of pages keyed by block number.
*/
union {
struct queue_entry p_list;
struct btree_node p_bnode;
/* btree_node contains three pointers, so provide three pointer-sized integers for
use if p_bnode isn't needed. */
uintptr_t priv1[3];
};
union {
/* used by bcache when sector size is < page size. bitmap of present/missing sectors */
DECLARE_BITMAP(p_blockbits, VM_MAX_SECTORS_PER_PAGE);
uint32_t p_priv2;
};
union {
/* sector address, used by bcache */
sectors_t p_blockid;
uint32_t p_priv3[2];
};
} __attribute__((aligned(2 * sizeof(unsigned long))));
/* represents a sector of memory, containing its own array of vm_pages.
this struct is used under the sparse memory model, instead of the
global vm_page array */
struct vm_sector {
/* sector size. this must be a power of 2.
all sectors in the system have the same size. */
enum vm_page_order s_size;
/* PFN of the first page contained in s_pages.
to find the PFN of any page contained within s_pages,
simply add its offset within the array to s_first_pfn */
size_t s_first_pfn;
/* array of pages contained in this sector */
struct vm_page *s_pages;
};
extern kern_status_t vm_bootstrap(const struct vm_zone_descriptor *zones, size_t nr_zones);
extern enum vm_model vm_memory_model(void);
extern void vm_set_memory_model(enum vm_model model);
extern struct vm_pg_data *vm_pg_data_get(vm_node_id_t node);
extern phys_addr_t vm_virt_to_phys(void *p);
extern void *vm_phys_to_virt(phys_addr_t p);
extern void vm_page_init_array();
extern struct vm_page *vm_page_get(phys_addr_t addr);
extern phys_addr_t vm_page_get_paddr(struct vm_page *pg);
extern struct vm_zone *vm_page_get_zone(struct vm_page *pg);
extern void *vm_page_get_vaddr(struct vm_page *pg);
extern size_t vm_page_get_pfn(struct vm_page *pg);
extern size_t vm_page_order_to_bytes(enum vm_page_order order);
extern size_t vm_page_order_to_pages(enum vm_page_order order);
extern vm_alignment_t vm_page_order_to_alignment(enum vm_page_order order);
extern struct vm_page *vm_page_alloc(enum vm_page_order order, enum vm_flags flags);
extern void vm_page_free(struct vm_page *pg);
extern int vm_page_split(struct vm_page *pg, struct vm_page **a, struct vm_page **b);
extern struct vm_page *vm_page_merge(struct vm_page *a, struct vm_page *b);
extern struct vm_page *vm_page_get_buddy(struct vm_page *pg);
extern struct vm_page *vm_page_get_next_tail(struct vm_page *pg);
extern size_t vm_bytes_to_pages(size_t bytes);
extern void vm_zone_init(struct vm_zone *z, const struct vm_zone_descriptor *zone_info);
extern struct vm_page *vm_zone_alloc_page(struct vm_zone *z, enum vm_page_order order, enum vm_flags flags);
extern void vm_zone_free_page(struct vm_zone *z, struct vm_page *pg);
extern struct vm_cache *vm_cache_create(const char *name, size_t objsz, enum vm_cache_flags flags);
extern void vm_cache_init(struct vm_cache *cache);
extern void vm_cache_destroy(struct vm_cache *cache);
extern void *vm_cache_alloc(struct vm_cache *cache, enum vm_flags flags);
extern void vm_cache_free(struct vm_cache *cache, void *p);
extern void kmalloc_init(void);
extern void *kmalloc(size_t count, enum vm_flags flags);
extern void *kzalloc(size_t count, enum vm_flags flags);
extern void kfree(void *p);
/* Flat memory model functions */
extern void vm_flat_init(void);
extern struct vm_page *vm_page_get_flat(phys_addr_t addr);
extern size_t vm_page_get_pfn_flat(struct vm_page *pg);
/* Sparse memory model functions */
extern void vm_sparse_init(void);
extern struct vm_page *vm_page_get_sparse(phys_addr_t addr);
extern size_t vm_page_get_pfn_sparse(struct vm_page *pg);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
inline void *operator new(size_t count, void *p) { return p; }
#define kmalloc_object(objtype, flags, ...) \
__extension__({ \
void *p = kmalloc(sizeof(objtype), flags); \
if (p) { \
new (p) objtype(__VA_ARGS__); \
} \
(objtype *)p; \
})
#endif
#endif