meta: rename
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user