Compare commits
7 Commits
62ec4c93ab
...
af0d97d6f5
| Author | SHA1 | Date | |
|---|---|---|---|
| af0d97d6f5 | |||
| c7d4463f7e | |||
| 8811016b7d | |||
| e1aeac9562 | |||
| 0ba46e065c | |||
| 675a6de47e | |||
| 4d12cab7f7 |
@@ -1,12 +1,18 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(magenta C ASM)
|
project(mango C ASM)
|
||||||
|
|
||||||
|
if (NOT BUILD_TOOLS_DIR)
|
||||||
|
message(FATAL_ERROR "No build tools directory specified. Please run build.sh")
|
||||||
|
endif ()
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 17)
|
set(CMAKE_C_STANDARD 17)
|
||||||
|
|
||||||
set(kernel_name "Magenta")
|
set(kernel_arch x86_64)
|
||||||
set(kernel_exe_name "magenta_kernel")
|
|
||||||
|
|
||||||
set(generic_src_dirs ds init kernel libc obj sched util vm)
|
set(kernel_name "Mango")
|
||||||
|
set(kernel_exe_name "mango_kernel")
|
||||||
|
|
||||||
|
set(generic_src_dirs ds init kernel libc sched util vm)
|
||||||
set(kernel_sources "")
|
set(kernel_sources "")
|
||||||
set(kernel_headers "")
|
set(kernel_headers "")
|
||||||
|
|
||||||
@@ -19,7 +25,6 @@ foreach (dir ${generic_src_dirs})
|
|||||||
set(kernel_headers ${kernel_headers} ${dir_headers})
|
set(kernel_headers ${kernel_headers} ${dir_headers})
|
||||||
endforeach (dir)
|
endforeach (dir)
|
||||||
|
|
||||||
set(kernel_arch x86_64)
|
|
||||||
file(GLOB_RECURSE arch_sources_c arch/${kernel_arch}/*.c)
|
file(GLOB_RECURSE arch_sources_c arch/${kernel_arch}/*.c)
|
||||||
file(GLOB_RECURSE arch_sources_asm arch/${kernel_arch}/*.S)
|
file(GLOB_RECURSE arch_sources_asm arch/${kernel_arch}/*.S)
|
||||||
file(GLOB_RECURSE arch_headers arch/${kernel_arch}/*.h)
|
file(GLOB_RECURSE arch_headers arch/${kernel_arch}/*.h)
|
||||||
@@ -40,7 +45,14 @@ target_include_directories(${kernel_exe_name} PRIVATE
|
|||||||
target_compile_options(${kernel_exe_name} PRIVATE
|
target_compile_options(${kernel_exe_name} PRIVATE
|
||||||
-nostdlib -ffreestanding
|
-nostdlib -ffreestanding
|
||||||
-Wall -Werror -pedantic -Wno-language-extension-token -Wno-unused-function -Wno-gnu-statement-expression
|
-Wall -Werror -pedantic -Wno-language-extension-token -Wno-unused-function -Wno-gnu-statement-expression
|
||||||
-O2 -g -fPIC -Iinclude -Iarch/${kernel_arch}/include -Ilibc/include)
|
-g -fPIC -Iinclude -Iarch/${kernel_arch}/include -Ilibc/include)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${kernel_exe_name}
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${kernel_exe_name}> $<TARGET_FILE:${kernel_exe_name}>.debug
|
||||||
|
COMMAND ${CMAKE_STRIP} -g $<TARGET_FILE:${kernel_exe_name}>)
|
||||||
|
|
||||||
target_link_libraries(${kernel_exe_name} -nostdlib -ffreestanding -lgcc)
|
target_link_libraries(${kernel_exe_name} -nostdlib -ffreestanding -lgcc)
|
||||||
target_compile_definitions(${kernel_exe_name} PRIVATE BUILD_ID="0")
|
target_compile_definitions(${kernel_exe_name} PRIVATE BUILD_ID="0")
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,8 @@ target_compile_options(${kernel_exe_name} PRIVATE
|
|||||||
-mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234)
|
-mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234)
|
||||||
target_link_libraries(${kernel_exe_name} "-z max-page-size=0x1000" "-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/layout.ld")
|
target_link_libraries(${kernel_exe_name} "-z max-page-size=0x1000" "-T ${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/layout.ld")
|
||||||
|
|
||||||
|
add_custom_command(TARGET ${kernel_exe_name} POST_BUILD
|
||||||
|
COMMAND ${BUILD_TOOLS_DIR}/e64patch $<TARGET_FILE:${kernel_exe_name}>
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMENT "Patching kernel elf64 image"
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "arch/serial.h"
|
|
||||||
|
|
||||||
#include <arch/e820.h>
|
#include <arch/e820.h>
|
||||||
#include <arch/pit.h>
|
#include <arch/pit.h>
|
||||||
|
#include <arch/serial.h>
|
||||||
|
#include <arch/vgacon.h>
|
||||||
#include <mango/arg.h>
|
#include <mango/arg.h>
|
||||||
#include <mango/clock.h>
|
#include <mango/clock.h>
|
||||||
#include <mango/console.h>
|
#include <mango/console.h>
|
||||||
@@ -52,11 +52,12 @@ void early_console_init(void)
|
|||||||
{
|
{
|
||||||
const char *dest = arg_value("kernel.early-console");
|
const char *dest = arg_value("kernel.early-console");
|
||||||
if (!dest) {
|
if (!dest) {
|
||||||
dest = "ttyS0";
|
dest = "tty0";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(dest, "tty0")) {
|
if (!strcmp(dest, "tty0")) {
|
||||||
/* show log messages on VGA */
|
/* show log messages on VGA */
|
||||||
|
vgacon_init();
|
||||||
} else if (!strcmp(dest, "ttyS0")) {
|
} else if (!strcmp(dest, "ttyS0")) {
|
||||||
/* write log messages to serial port */
|
/* write log messages to serial port */
|
||||||
early_serialcon_init(115200);
|
early_serialcon_init(115200);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#include <mango/types.h>
|
#include <mango/compiler.h>
|
||||||
#include <mango/memblock.h>
|
#include <mango/memblock.h>
|
||||||
#include <mango/vm.h>
|
#include <mango/pmap.h>
|
||||||
#include <mango/printk.h>
|
#include <mango/printk.h>
|
||||||
#include <mango/status.h>
|
#include <mango/status.h>
|
||||||
#include <mango/compiler.h>
|
#include <mango/types.h>
|
||||||
#include <mango/pmap.h>
|
#include <mango/vm.h>
|
||||||
|
|
||||||
/* some helpful datasize constants */
|
/* some helpful datasize constants */
|
||||||
#define C_1GiB 0x40000000ULL
|
#define C_1GiB 0x40000000ULL
|
||||||
@@ -33,7 +33,7 @@ static size_t ps_size(enum page_size ps)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static pmap_t alloc_pmap()
|
static pmap_t alloc_pmap(void)
|
||||||
{
|
{
|
||||||
struct pml4t *p = kzalloc(sizeof *p, 0);
|
struct pml4t *p = kzalloc(sizeof *p, 0);
|
||||||
return vm_virt_to_phys(p);
|
return vm_virt_to_phys(p);
|
||||||
@@ -45,12 +45,14 @@ static pte_t make_pte(pfn_t pfn, enum vm_prot prot, enum page_size size)
|
|||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case PS_1G:
|
case PS_1G:
|
||||||
/* pfn_t is in terms of 4KiB pages, convert to 1GiB page frame number */
|
/* pfn_t is in terms of 4KiB pages, convert to 1GiB page frame
|
||||||
|
* number */
|
||||||
pfn >>= 18;
|
pfn >>= 18;
|
||||||
v = (pfn & 0x3FFFFF) << 30;
|
v = (pfn & 0x3FFFFF) << 30;
|
||||||
break;
|
break;
|
||||||
case PS_2M:
|
case PS_2M:
|
||||||
/* pfn_t is in terms of 4KiB pages, convert to 2MiB page frame number */
|
/* pfn_t is in terms of 4KiB pages, convert to 2MiB page frame
|
||||||
|
* number */
|
||||||
pfn >>= 9;
|
pfn >>= 9;
|
||||||
v = (pfn & 0x7FFFFFFF) << 21;
|
v = (pfn & 0x7FFFFFFF) << 21;
|
||||||
break;
|
break;
|
||||||
@@ -129,14 +131,16 @@ static void delete_pdir(phys_addr_t pd)
|
|||||||
kfree(pdir);
|
kfree(pdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
static kern_status_t do_pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot prot, enum page_size size)
|
static kern_status_t do_pmap_add(
|
||||||
|
pmap_t pmap,
|
||||||
|
void *p,
|
||||||
|
pfn_t pfn,
|
||||||
|
enum vm_prot prot,
|
||||||
|
enum page_size size)
|
||||||
{
|
{
|
||||||
uintptr_t pv = (uintptr_t)p;
|
uintptr_t pv = (uintptr_t)p;
|
||||||
unsigned int
|
unsigned int pml4t_index = BAD_INDEX, pdpt_index = BAD_INDEX,
|
||||||
pml4t_index = BAD_INDEX,
|
pd_index = BAD_INDEX, pt_index = BAD_INDEX;
|
||||||
pdpt_index = BAD_INDEX,
|
|
||||||
pd_index = BAD_INDEX,
|
|
||||||
pt_index = BAD_INDEX;
|
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case PS_4K:
|
case PS_4K:
|
||||||
@@ -171,16 +175,19 @@ static kern_status_t do_pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot p
|
|||||||
struct pdpt *pdpt = NULL;
|
struct pdpt *pdpt = NULL;
|
||||||
if (!pml4t->p_entries[pml4t_index]) {
|
if (!pml4t->p_entries[pml4t_index]) {
|
||||||
pdpt = kzalloc(sizeof *pdpt, 0);
|
pdpt = kzalloc(sizeof *pdpt, 0);
|
||||||
pml4t->p_entries[pml4t_index] = PTR_TO_ENTRY(vm_virt_to_phys(pdpt));
|
pml4t->p_entries[pml4t_index]
|
||||||
|
= PTR_TO_ENTRY(vm_virt_to_phys(pdpt));
|
||||||
} else {
|
} else {
|
||||||
pdpt = vm_phys_to_virt(ENTRY_TO_PTR(pml4t->p_entries[pml4t_index]));
|
pdpt = vm_phys_to_virt(
|
||||||
|
ENTRY_TO_PTR(pml4t->p_entries[pml4t_index]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we're mapping a 1GiB page, we stop here */
|
/* if we're mapping a 1GiB page, we stop here */
|
||||||
if (size == PS_1G) {
|
if (size == PS_1G) {
|
||||||
if (pdpt->p_entries[pdpt_index] != 0) {
|
if (pdpt->p_entries[pdpt_index] != 0) {
|
||||||
/* this slot points to a pdir, delete it.
|
/* this slot points to a pdir, delete it.
|
||||||
if this slot points to a hugepage, this does nothing */
|
if this slot points to a hugepage, this does nothing
|
||||||
|
*/
|
||||||
delete_pdir(pdpt->p_entries[pdpt_index]);
|
delete_pdir(pdpt->p_entries[pdpt_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,22 +196,25 @@ static kern_status_t do_pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot p
|
|||||||
return KERN_OK;
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 3. traverse PDPT, get PDIR (optional, 4K and 2M only) */
|
/* 3. traverse PDPT, get PDIR (optional, 4K and 2M only) */
|
||||||
struct pdir *pdir = NULL;
|
struct pdir *pdir = NULL;
|
||||||
if (!pdpt->p_entries[pdpt_index] || pdpt->p_pages[pdpt_index] & PTE_PAGESIZE) {
|
if (!pdpt->p_entries[pdpt_index]
|
||||||
|
|| pdpt->p_pages[pdpt_index] & PTE_PAGESIZE) {
|
||||||
/* entry is null, or points to a hugepage */
|
/* entry is null, or points to a hugepage */
|
||||||
pdir = kzalloc(sizeof *pdir, 0);
|
pdir = kzalloc(sizeof *pdir, 0);
|
||||||
pdpt->p_entries[pdpt_index] = PTR_TO_ENTRY(vm_virt_to_phys(pdir));
|
pdpt->p_entries[pdpt_index]
|
||||||
|
= PTR_TO_ENTRY(vm_virt_to_phys(pdir));
|
||||||
} else {
|
} else {
|
||||||
pdir = vm_phys_to_virt(ENTRY_TO_PTR(pdpt->p_entries[pdpt_index]));
|
pdir = vm_phys_to_virt(
|
||||||
|
ENTRY_TO_PTR(pdpt->p_entries[pdpt_index]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we're mapping a 2MiB page, we stop here */
|
/* if we're mapping a 2MiB page, we stop here */
|
||||||
if (size == PS_2M) {
|
if (size == PS_2M) {
|
||||||
if (pdir->p_entries[pd_index] != 0) {
|
if (pdir->p_entries[pd_index] != 0) {
|
||||||
/* this slot points to a ptab, delete it.
|
/* this slot points to a ptab, delete it.
|
||||||
if this slot points to a hugepage, this does nothing */
|
if this slot points to a hugepage, this does nothing
|
||||||
|
*/
|
||||||
delete_ptab(pdir->p_entries[pd_index]);
|
delete_ptab(pdir->p_entries[pd_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +224,8 @@ static kern_status_t do_pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot p
|
|||||||
|
|
||||||
/* 4. traverse PDIR, get PTAB (optional, 4K only) */
|
/* 4. traverse PDIR, get PTAB (optional, 4K only) */
|
||||||
struct ptab *ptab = NULL;
|
struct ptab *ptab = NULL;
|
||||||
if (!pdir->p_entries[pd_index] || pdir->p_pages[pd_index] & PTE_PAGESIZE) {
|
if (!pdir->p_entries[pd_index]
|
||||||
|
|| pdir->p_pages[pd_index] & PTE_PAGESIZE) {
|
||||||
/* entry is null, or points to a hugepage */
|
/* entry is null, or points to a hugepage */
|
||||||
ptab = kzalloc(sizeof *ptab, 0);
|
ptab = kzalloc(sizeof *ptab, 0);
|
||||||
pdir->p_entries[pd_index] = PTR_TO_ENTRY(vm_virt_to_phys(ptab));
|
pdir->p_entries[pd_index] = PTR_TO_ENTRY(vm_virt_to_phys(ptab));
|
||||||
@@ -234,7 +245,8 @@ pmap_t get_kernel_pmap(void)
|
|||||||
void pmap_bootstrap(void)
|
void pmap_bootstrap(void)
|
||||||
{
|
{
|
||||||
can_use_gbpages = gigabyte_pages();
|
can_use_gbpages = gigabyte_pages();
|
||||||
printk("pmap: gigabyte pages %sabled", can_use_gbpages == 1 ? "en" : "dis");
|
printk("pmap: gigabyte pages %sabled",
|
||||||
|
can_use_gbpages == 1 ? "en" : "dis");
|
||||||
enable_nx();
|
enable_nx();
|
||||||
printk("pmap: NX protection enabled");
|
printk("pmap: NX protection enabled");
|
||||||
|
|
||||||
@@ -251,16 +263,19 @@ void pmap_bootstrap(void)
|
|||||||
the kernel and memblock-allocated data. */
|
the kernel and memblock-allocated data. */
|
||||||
uintptr_t vbase = VM_KERNEL_VOFFSET;
|
uintptr_t vbase = VM_KERNEL_VOFFSET;
|
||||||
for (size_t i = 0; i < C_2GiB; i += hugepage_sz) {
|
for (size_t i = 0; i < C_2GiB; i += hugepage_sz) {
|
||||||
do_pmap_add(kernel_pmap,
|
do_pmap_add(
|
||||||
|
kernel_pmap,
|
||||||
(void *)(vbase + i),
|
(void *)(vbase + i),
|
||||||
PFN(i),
|
PFN(i),
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC | VM_PROT_SVR,
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXEC
|
||||||
|
| VM_PROT_SVR,
|
||||||
hugepage);
|
hugepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
phys_addr_t pmem_limit = 0x0;
|
phys_addr_t pmem_limit = 0x0;
|
||||||
struct memblock_iter it;
|
struct memblock_iter it;
|
||||||
for_each_mem_range(&it, 0x00, UINTPTR_MAX) {
|
for_each_mem_range(&it, 0x00, UINTPTR_MAX)
|
||||||
|
{
|
||||||
if (it.it_limit > pmem_limit) {
|
if (it.it_limit > pmem_limit) {
|
||||||
pmem_limit = it.it_limit;
|
pmem_limit = it.it_limit;
|
||||||
}
|
}
|
||||||
@@ -268,10 +283,13 @@ void pmap_bootstrap(void)
|
|||||||
|
|
||||||
vbase = VM_PAGEMAP_BASE;
|
vbase = VM_PAGEMAP_BASE;
|
||||||
for (size_t i = 0; i < pmem_limit; i += hugepage_sz) {
|
for (size_t i = 0; i < pmem_limit; i += hugepage_sz) {
|
||||||
do_pmap_add(kernel_pmap,
|
do_pmap_add(
|
||||||
|
kernel_pmap,
|
||||||
(void *)(vbase + i),
|
(void *)(vbase + i),
|
||||||
PFN(i),
|
PFN(i),
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_SVR | VM_PROT_NOCACHE, hugepage);
|
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_SVR
|
||||||
|
| VM_PROT_NOCACHE,
|
||||||
|
hugepage);
|
||||||
}
|
}
|
||||||
|
|
||||||
pmap_switch(kernel_pmap);
|
pmap_switch(kernel_pmap);
|
||||||
@@ -284,10 +302,14 @@ pmap_t pmap_create(void)
|
|||||||
|
|
||||||
void pmap_destroy(pmap_t pmap)
|
void pmap_destroy(pmap_t pmap)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kern_status_t pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot prot, enum pmap_flags flags)
|
kern_status_t pmap_add(
|
||||||
|
pmap_t pmap,
|
||||||
|
void *p,
|
||||||
|
pfn_t pfn,
|
||||||
|
enum vm_prot prot,
|
||||||
|
enum pmap_flags flags)
|
||||||
{
|
{
|
||||||
enum page_size ps = PS_4K;
|
enum page_size ps = PS_4K;
|
||||||
if (flags & PMAP_HUGEPAGE) {
|
if (flags & PMAP_HUGEPAGE) {
|
||||||
@@ -297,7 +319,13 @@ kern_status_t pmap_add(pmap_t pmap, void *p, pfn_t pfn, enum vm_prot prot, enum
|
|||||||
return do_pmap_add(pmap, p, pfn, prot, ps);
|
return do_pmap_add(pmap, p, pfn, prot, ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
return KERN_OK;
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,50 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uint8_t inportb(uint16_t port) {
|
uint8_t inportb(uint16_t port)
|
||||||
|
{
|
||||||
uint8_t data;
|
uint8_t data;
|
||||||
__asm__ __volatile__("inb %1, %0" : "=a"(data) : "dN"(port));
|
__asm__ __volatile__("inb %1, %0" : "=a"(data) : "dN"(port));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void outportb(uint16_t port, uint8_t data) {
|
void outportb(uint16_t port, uint8_t data)
|
||||||
|
{
|
||||||
__asm__ __volatile__("outb %1, %0" : : "dN"(port), "a"(data));
|
__asm__ __volatile__("outb %1, %0" : : "dN"(port), "a"(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t inportw(uint16_t port) {
|
uint16_t inportw(uint16_t port)
|
||||||
|
{
|
||||||
uint16_t data;
|
uint16_t data;
|
||||||
__asm__ __volatile__("inw %1, %0" : "=a"(data) : "dN"(port));
|
__asm__ __volatile__("inw %1, %0" : "=a"(data) : "dN"(port));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void outportw(uint16_t port, uint16_t data) {
|
void outportw(uint16_t port, uint16_t data)
|
||||||
|
{
|
||||||
__asm__ __volatile__("outw %1, %0" : : "dN"(port), "a"(data));
|
__asm__ __volatile__("outw %1, %0" : : "dN"(port), "a"(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t inportl(uint16_t port) {
|
uint32_t inportl(uint16_t port)
|
||||||
|
{
|
||||||
uint32_t data;
|
uint32_t data;
|
||||||
__asm__ __volatile__("inl %%dx, %%eax" : "=a"(data) : "dN"(port));
|
__asm__ __volatile__("inl %%dx, %%eax" : "=a"(data) : "dN"(port));
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void outportl(uint16_t port, uint32_t data) {
|
void outportl(uint16_t port, uint32_t data)
|
||||||
|
{
|
||||||
__asm__ __volatile__("outl %%eax, %%dx" : : "dN"(port), "a"(data));
|
__asm__ __volatile__("outl %%eax, %%dx" : : "dN"(port), "a"(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
void outportsw(uint16_t port, void *data, uint32_t size) {
|
void outportsw(uint16_t port, void *data, uint32_t size)
|
||||||
|
{
|
||||||
__asm__ __volatile__("rep outsw" : "+S"(data), "+c"(size) : "d"(port));
|
__asm__ __volatile__("rep outsw" : "+S"(data), "+c"(size) : "d"(port));
|
||||||
}
|
}
|
||||||
|
|
||||||
void inportsw(uint16_t port, unsigned char *data, unsigned long size) {
|
void inportsw(uint16_t port, unsigned char *data, unsigned long size)
|
||||||
__asm__ __volatile__("rep insw" : "+D"(data), "+c"(size) : "d"(port) : "memory");
|
{
|
||||||
|
__asm__ __volatile__("rep insw"
|
||||||
|
: "+D"(data), "+c"(size)
|
||||||
|
: "d"(port)
|
||||||
|
: "memory");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
#include <arch/irq.h>
|
#include <arch/irq.h>
|
||||||
#include <arch/ports.h>
|
#include <arch/ports.h>
|
||||||
#include <arch/serial.h>
|
#include <arch/serial.h>
|
||||||
#include <mango/device.h>
|
|
||||||
#include <mango/kext.h>
|
|
||||||
#include <mango/libc/stdio.h>
|
#include <mango/libc/stdio.h>
|
||||||
#include <mango/printk.h>
|
#include <mango/printk.h>
|
||||||
#include <mango/tty.h>
|
|
||||||
|
|
||||||
#define COM1 0x3F8
|
#define COM1 0x3F8
|
||||||
#define COM2 0x2F8
|
#define COM2 0x2F8
|
||||||
|
|||||||
@@ -1,7 +1,21 @@
|
|||||||
find_program(QEMU qemu-system-x86_64)
|
find_program(QEMU qemu-system-x86_64)
|
||||||
|
set(DEBUG_SESSION ${CMAKE_SOURCE_DIR}/tools/kernel-debug/debug_session.sh)
|
||||||
|
set(DEBUG_CFG_GDB ${CMAKE_SOURCE_DIR}/tools/kernel-debug/gdb_session_init)
|
||||||
|
set(DEBUG_CFG_LLDB ${CMAKE_SOURCE_DIR}/tools/kernel-debug/lldb_session_init)
|
||||||
|
|
||||||
add_custom_target(run
|
add_custom_target(run
|
||||||
USES_TERMINAL
|
USES_TERMINAL
|
||||||
COMMAND ${QEMU}
|
COMMAND ${QEMU}
|
||||||
-kernel $<TARGET_FILE:${kernel_exe_name}>
|
-kernel $<TARGET_FILE:${kernel_exe_name}>
|
||||||
-serial stdio)
|
-serial stdio)
|
||||||
|
|
||||||
|
# LLDB DEPENDS ON AN ELF64 EXECUTABLE.
|
||||||
|
# .DBG FILE MUST NOT BE PATCHED WITH E64PATCH!
|
||||||
|
add_custom_target(debug
|
||||||
|
USES_TERMINAL
|
||||||
|
COMMAND ${DEBUG_SESSION}
|
||||||
|
${DEBUG_CFG_GDB}
|
||||||
|
${DEBUG_CFG_LLDB}
|
||||||
|
${QEMU} -kernel $<TARGET_FILE:${kernel_exe_name}>
|
||||||
|
-S -s
|
||||||
|
-monitor stdio)
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
# the name of the target operating system
|
# the name of the target operating system
|
||||||
set(CMAKE_SYSTEM_NAME Magenta)
|
set(CMAKE_SYSTEM_NAME Mango)
|
||||||
|
|
||||||
# which compilers to use for C and C++
|
# which compilers to use for C and C++
|
||||||
set(CMAKE_C_COMPILER x86_64-elf-gcc)
|
set(CMAKE_C_COMPILER x86_64-elf-gcc)
|
||||||
set(CMAKE_ASM_COMPILER x86_64-elf-gcc)
|
set(CMAKE_ASM_COMPILER x86_64-elf-gcc)
|
||||||
set(CMAKE_CXX_COMPILER x86_64-elf-g++)
|
set(CMAKE_CXX_COMPILER x86_64-elf-g++)
|
||||||
|
|
||||||
|
set(CMAKE_STRIP x86_64-elf-strip)
|
||||||
|
|
||||||
set(CMAKE_C_COMPILER_WORKS TRUE)
|
set(CMAKE_C_COMPILER_WORKS TRUE)
|
||||||
set(CMAKE_CXX_COMPILER_WORKS TRUE)
|
set(CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||||
|
|
||||||
|
|||||||
126
arch/x86_64/vga.c
Normal file
126
arch/x86_64/vga.c
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#include <arch/irq.h>
|
||||||
|
#include <arch/ports.h>
|
||||||
|
#include <arch/serial.h>
|
||||||
|
#include <mango/libc/stdio.h>
|
||||||
|
#include <mango/machine/vm.h>
|
||||||
|
#include <mango/printk.h>
|
||||||
|
|
||||||
|
struct vga_console {
|
||||||
|
uint16_t *vga_framebuffer;
|
||||||
|
unsigned int vga_cursor_x, vga_cursor_y;
|
||||||
|
unsigned int vga_screen_width, vga_screen_height;
|
||||||
|
uint8_t vga_attrib;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct vga_console vga_con = {
|
||||||
|
.vga_attrib = 0x0F,
|
||||||
|
.vga_screen_width = 80,
|
||||||
|
.vga_screen_height = 25,
|
||||||
|
.vga_framebuffer = (uint16_t *)0xffffffff800b8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void vga_console_clear(struct vga_console *con)
|
||||||
|
{
|
||||||
|
size_t len = con->vga_screen_width * con->vga_screen_height;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
con->vga_framebuffer[i] = (uint16_t)con->vga_attrib << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->vga_cursor_x = 0;
|
||||||
|
con->vga_cursor_y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vga_console_show_cursor(struct vga_console *con)
|
||||||
|
{
|
||||||
|
size_t start = 0, end = 15;
|
||||||
|
|
||||||
|
outportb(0x3D4, 0x0A);
|
||||||
|
outportb(0x3D5, (inportb(0x3D5) & 0xC0) | start);
|
||||||
|
|
||||||
|
outportb(0x3D4, 0x0B);
|
||||||
|
outportb(0x3D5, (inportb(0x3D5) & 0xE0) | end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vga_console_update_cursor(struct vga_console *con)
|
||||||
|
{
|
||||||
|
uint16_t pos
|
||||||
|
= con->vga_cursor_y * con->vga_screen_width + con->vga_cursor_x;
|
||||||
|
|
||||||
|
outportb(0x3D4, 0x0F);
|
||||||
|
outportb(0x3D5, (uint8_t)(pos & 0xFF));
|
||||||
|
outportb(0x3D4, 0x0E);
|
||||||
|
outportb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vga_console_scroll(struct vga_console *con)
|
||||||
|
{
|
||||||
|
uint16_t *src = &con->vga_framebuffer[con->vga_screen_width];
|
||||||
|
uint16_t *dest = &con->vga_framebuffer[0];
|
||||||
|
size_t len = (con->vga_screen_height - 1) * con->vga_screen_width
|
||||||
|
* sizeof *con->vga_framebuffer;
|
||||||
|
|
||||||
|
memcpy(dest, src, len);
|
||||||
|
|
||||||
|
dest = &con->vga_framebuffer
|
||||||
|
[(con->vga_screen_height - 1) * con->vga_screen_width];
|
||||||
|
len = con->vga_screen_width;
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
dest[i] = (uint16_t)con->vga_attrib << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
con->vga_cursor_x = 0;
|
||||||
|
con->vga_cursor_y = con->vga_screen_height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vga_console_putc(struct vga_console *con, char c)
|
||||||
|
{
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
con->vga_cursor_x = 0;
|
||||||
|
con->vga_cursor_y++;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
con->vga_cursor_x = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
con->vga_framebuffer
|
||||||
|
[con->vga_cursor_y * con->vga_screen_width
|
||||||
|
+ con->vga_cursor_x]
|
||||||
|
= ((uint16_t)con->vga_attrib << 8) | c;
|
||||||
|
con->vga_cursor_x++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->vga_cursor_x >= con->vga_screen_width) {
|
||||||
|
con->vga_cursor_x = 0;
|
||||||
|
con->vga_cursor_y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con->vga_cursor_y >= con->vga_screen_height) {
|
||||||
|
vga_console_scroll(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vgacon_write(struct console *con, const char *s, unsigned int len)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
|
vga_console_putc(&vga_con, s[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vga_console_update_cursor(&vga_con);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct console vgacon = {
|
||||||
|
.c_name = "vgacon",
|
||||||
|
.c_flags = CON_BOOT,
|
||||||
|
.c_write = vgacon_write,
|
||||||
|
.c_lock = SPIN_LOCK_INIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
void vgacon_init(void)
|
||||||
|
{
|
||||||
|
vga_console_clear(&vga_con);
|
||||||
|
vga_console_show_cursor(&vga_con);
|
||||||
|
console_register(&vgacon);
|
||||||
|
}
|
||||||
39
build.sh
Executable file
39
build.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
arch=$1
|
||||||
|
tools_src_dir="$(pwd)/tools"
|
||||||
|
kernel_src_dir="$(pwd)"
|
||||||
|
|
||||||
|
tools_build_dir="$(pwd)/build/tools"
|
||||||
|
kernel_build_dir="$(pwd)/build"
|
||||||
|
|
||||||
|
bin_dir="$kernel_build_dir/bin"
|
||||||
|
lib_dir="$kernel_build_dir/lib"
|
||||||
|
|
||||||
|
if [[ -z "$arch" ]]; then
|
||||||
|
echo "No architecture specified."
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $kernel_build_dir
|
||||||
|
mkdir -p $tools_build_dir
|
||||||
|
mkdir -p $kernel_build_dir
|
||||||
|
|
||||||
|
pushd $tools_build_dir
|
||||||
|
cmake \
|
||||||
|
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY="$bin_dir" \
|
||||||
|
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$lib_dir" \
|
||||||
|
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$lib_dir" \
|
||||||
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||||
|
$tools_src_dir
|
||||||
|
ninja
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd $kernel_build_dir
|
||||||
|
cmake \
|
||||||
|
-DBUILD_TOOLS_DIR="$bin_dir" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$kernel_src_dir/arch/$arch/toolchain.cmake" \
|
||||||
|
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||||
|
$kernel_src_dir
|
||||||
|
ninja
|
||||||
|
popd
|
||||||
59
doc/kernel-interface.txt
Executable file
59
doc/kernel-interface.txt
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
=== KERNEL TYPES ====
|
||||||
|
|
||||||
|
kern_handle_t
|
||||||
|
kern_status_t
|
||||||
|
kern_txnid_t
|
||||||
|
kern_clock_t
|
||||||
|
kern_msg_t
|
||||||
|
|
||||||
|
|
||||||
|
=== KERNEL ENUMS ====
|
||||||
|
|
||||||
|
kern_status_t:
|
||||||
|
KERN_SUCCESS
|
||||||
|
KERN_BAD_HANDLE
|
||||||
|
|
||||||
|
clockid_t:
|
||||||
|
CLOCK_REALTIME
|
||||||
|
CLOCK_MONOTONIC
|
||||||
|
|
||||||
|
|
||||||
|
=== KERNEL STRUCTS ====
|
||||||
|
|
||||||
|
kern_msg_t {
|
||||||
|
void *buf;
|
||||||
|
size_t len;
|
||||||
|
kern_handle_t *handles;
|
||||||
|
size_t nhandles
|
||||||
|
}
|
||||||
|
|
||||||
|
=== KERNEL OBJECTS ====
|
||||||
|
|
||||||
|
port
|
||||||
|
timer
|
||||||
|
address_space
|
||||||
|
page_buf
|
||||||
|
task
|
||||||
|
thread
|
||||||
|
event
|
||||||
|
|
||||||
|
=== KERNEL SYSTEM CALLS ====
|
||||||
|
|
||||||
|
handle_close
|
||||||
|
|
||||||
|
port_create
|
||||||
|
port_publish
|
||||||
|
port_connect
|
||||||
|
|
||||||
|
msg_send
|
||||||
|
msg_recv
|
||||||
|
msg_read
|
||||||
|
msg_write
|
||||||
|
|
||||||
|
timer_create
|
||||||
|
timer_arm
|
||||||
|
|
||||||
|
clock_gettime
|
||||||
|
|
||||||
|
task_get
|
||||||
|
task_move_handle
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,336 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
#ifndef MANGO_OBJECT_H_
|
#ifndef MANGO_OBJECT_H_
|
||||||
#define MANGO_OBJECT_H_
|
#define MANGO_OBJECT_H_
|
||||||
|
|
||||||
|
#include <mango/flags.h>
|
||||||
#include <mango/locks.h>
|
#include <mango/locks.h>
|
||||||
#include <mango/status.h>
|
#include <mango/status.h>
|
||||||
#include <mango/flags.h>
|
|
||||||
#include <mango/vm.h>
|
#include <mango/vm.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -18,9 +18,9 @@ extern "C" {
|
|||||||
#define OBJECT_CAST(to_type, to_type_member, p) \
|
#define OBJECT_CAST(to_type, to_type_member, p) \
|
||||||
((to_type *)((uintptr_t)p) - offsetof(to_type, to_type_member))
|
((to_type *)((uintptr_t)p) - offsetof(to_type, to_type_member))
|
||||||
#define OBJECT_C_CAST(c_type, c_type_member, obj_type, objp) \
|
#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
|
OBJECT_IS_TYPE(objp, obj_type) \
|
||||||
#define OBJECT_IS_TYPE(obj, type_ptr) \
|
? OBJECT_CAST(c_type, c_type_member, (objp)) : NULL
|
||||||
((obj)->ob_type == (type_ptr))
|
#define OBJECT_IS_TYPE(obj, type_ptr) ((obj)->ob_type == (type_ptr))
|
||||||
|
|
||||||
struct object;
|
struct object;
|
||||||
struct object_attrib;
|
struct object_attrib;
|
||||||
@@ -30,22 +30,7 @@ enum object_type_flags {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct object_ops {
|
struct object_ops {
|
||||||
kern_status_t(*open)(struct object *obj);
|
kern_status_t (*destroy)(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 {
|
struct object_type {
|
||||||
@@ -55,7 +40,6 @@ struct object_type {
|
|||||||
unsigned int ob_header_offset;
|
unsigned int ob_header_offset;
|
||||||
struct vm_cache ob_cache;
|
struct vm_cache ob_cache;
|
||||||
struct queue_entry ob_list;
|
struct queue_entry ob_list;
|
||||||
struct queue ob_attrib;
|
|
||||||
struct object_ops ob_ops;
|
struct object_ops ob_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,7 +49,6 @@ struct object {
|
|||||||
spin_lock_t ob_lock;
|
spin_lock_t ob_lock;
|
||||||
unsigned int ob_refcount;
|
unsigned int ob_refcount;
|
||||||
unsigned int ob_handles;
|
unsigned int ob_handles;
|
||||||
struct queue ob_attrib;
|
|
||||||
struct queue_entry ob_list;
|
struct queue_entry ob_list;
|
||||||
} __aligned(sizeof(long));
|
} __aligned(sizeof(long));
|
||||||
|
|
||||||
@@ -73,14 +56,6 @@ extern kern_status_t object_bootstrap(void);
|
|||||||
extern kern_status_t object_type_register(struct object_type *p);
|
extern kern_status_t object_type_register(struct object_type *p);
|
||||||
extern kern_status_t object_type_unregister(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_create(struct object_type *type);
|
||||||
extern struct object *object_ref(struct object *obj);
|
extern struct object *object_ref(struct object *obj);
|
||||||
extern void object_deref(struct object *obj);
|
extern void object_deref(struct object *obj);
|
||||||
@@ -88,28 +63,6 @@ extern void object_lock(struct object *obj);
|
|||||||
extern void object_unlock(struct object *obj);
|
extern void object_unlock(struct object *obj);
|
||||||
extern void object_lock_irqsave(struct object *obj, unsigned long *flags);
|
extern void object_lock_irqsave(struct object *obj, unsigned long *flags);
|
||||||
extern void object_unlock_irqrestore(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
#include <mango/arg.h>
|
#include <mango/arg.h>
|
||||||
#include <mango/clock.h>
|
#include <mango/clock.h>
|
||||||
#include <mango/cpu.h>
|
#include <mango/cpu.h>
|
||||||
#include <mango/device.h>
|
|
||||||
#include <mango/init.h>
|
#include <mango/init.h>
|
||||||
#include <mango/input.h>
|
#include <mango/input.h>
|
||||||
#include <mango/kext.h>
|
|
||||||
#include <mango/libc/stdio.h>
|
#include <mango/libc/stdio.h>
|
||||||
#include <mango/machine/init.h>
|
#include <mango/machine/init.h>
|
||||||
#include <mango/object.h>
|
#include <mango/object.h>
|
||||||
@@ -12,7 +10,6 @@
|
|||||||
#include <mango/printk.h>
|
#include <mango/printk.h>
|
||||||
#include <mango/sched.h>
|
#include <mango/sched.h>
|
||||||
#include <mango/test.h>
|
#include <mango/test.h>
|
||||||
#include <mango/tty.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern unsigned long get_rflags(void);
|
extern unsigned long get_rflags(void);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
#include <mango/locks.h>
|
||||||
#include <mango/object.h>
|
#include <mango/object.h>
|
||||||
#include <mango/queue.h>
|
#include <mango/queue.h>
|
||||||
#include <mango/locks.h>
|
|
||||||
|
|
||||||
#define HAS_OP(obj, opname) ((obj)->ob_type->ob_ops.opname)
|
#define HAS_OP(obj, opname) ((obj)->ob_type->ob_ops.opname)
|
||||||
|
|
||||||
@@ -9,9 +9,6 @@ static spin_lock_t object_types_lock = SPIN_LOCK_INIT;
|
|||||||
|
|
||||||
kern_status_t object_bootstrap(void)
|
kern_status_t object_bootstrap(void)
|
||||||
{
|
{
|
||||||
init_set_objects();
|
|
||||||
init_link_objects();
|
|
||||||
init_global_namespace();
|
|
||||||
return KERN_OK;
|
return KERN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +53,8 @@ struct object *object_create(struct object_type *type)
|
|||||||
|
|
||||||
memset(obj_buf, 0x00, type->ob_size);
|
memset(obj_buf, 0x00, type->ob_size);
|
||||||
|
|
||||||
struct object *obj = (struct object *)((unsigned char *)obj_buf + type->ob_header_offset);
|
struct object *obj = (struct object *)((unsigned char *)obj_buf
|
||||||
|
+ type->ob_header_offset);
|
||||||
|
|
||||||
obj->ob_type = type;
|
obj->ob_type = type;
|
||||||
obj->ob_lock = SPIN_LOCK_INIT;
|
obj->ob_lock = SPIN_LOCK_INIT;
|
||||||
@@ -131,64 +129,3 @@ struct object *object_header(void *p)
|
|||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
kern_status_t object_read(struct object *obj, void *p, size_t offset,
|
|
||||||
size_t max, size_t *nr_read, mango_flags_t flags)
|
|
||||||
{
|
|
||||||
kern_status_t status = KERN_UNSUPPORTED;
|
|
||||||
|
|
||||||
if (obj->ob_type->ob_ops.read) {
|
|
||||||
status = obj->ob_type->ob_ops.read(obj, p, offset, &max, flags);
|
|
||||||
} else {
|
|
||||||
max = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nr_read) {
|
|
||||||
*nr_read = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
kern_status_t status = KERN_UNSUPPORTED;
|
|
||||||
|
|
||||||
if (obj->ob_type->ob_ops.write) {
|
|
||||||
status = obj->ob_type->ob_ops.write(obj, p, offset, &max, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_get_child_named(struct object *obj, const char *name, struct object **out)
|
|
||||||
{
|
|
||||||
kern_status_t status = KERN_UNSUPPORTED;
|
|
||||||
|
|
||||||
if (HAS_OP(obj, get_named)) {
|
|
||||||
status = obj->ob_type->ob_ops.get_named(obj, name, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_get_child_at(struct object *obj, size_t at, struct object **out)
|
|
||||||
{
|
|
||||||
kern_status_t status = KERN_UNSUPPORTED;
|
|
||||||
|
|
||||||
if (HAS_OP(obj, get_at)) {
|
|
||||||
status = obj->ob_type->ob_ops.get_at(obj, at, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_query_name(struct object *obj, char name[OBJECT_NAME_MAX])
|
|
||||||
{
|
|
||||||
if (HAS_OP(obj, query_name)) {
|
|
||||||
return obj->ob_type->ob_ops.query_name(obj, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return KERN_UNSUPPORTED;
|
|
||||||
}
|
|
||||||
62
obj/link.c
62
obj/link.c
@@ -1,62 +0,0 @@
|
|||||||
#include <mango/object.h>
|
|
||||||
|
|
||||||
#define LINK_CAST(p) OBJECT_C_CAST(struct link, l_base, &link_type, p)
|
|
||||||
|
|
||||||
struct link {
|
|
||||||
struct object l_base;
|
|
||||||
char l_name[OBJECT_NAME_MAX];
|
|
||||||
struct object *l_dest;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct object_type link_type;
|
|
||||||
|
|
||||||
static kern_status_t link_query_name(struct object *obj, char out[OBJECT_NAME_MAX])
|
|
||||||
{
|
|
||||||
struct link *link = LINK_CAST(obj);
|
|
||||||
strncpy(out, link->l_name, OBJECT_NAME_MAX - 1);
|
|
||||||
out[OBJECT_NAME_MAX - 1] = 0;
|
|
||||||
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct object_type link_type = {
|
|
||||||
.ob_name = "link",
|
|
||||||
.ob_size = sizeof(struct link),
|
|
||||||
.ob_header_offset = offsetof(struct link, l_base),
|
|
||||||
.ob_ops = {
|
|
||||||
.query_name = link_query_name,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_link_objects(void)
|
|
||||||
{
|
|
||||||
object_type_register(&link_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object *link_create(const char *name, struct object *dest)
|
|
||||||
{
|
|
||||||
struct object *link_obj = object_create(&link_type);
|
|
||||||
if (!link_obj) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct link *link = LINK_CAST(link_obj);
|
|
||||||
|
|
||||||
strncpy(link->l_name, name, sizeof link->l_name - 1);
|
|
||||||
link->l_name[sizeof link->l_name - 1] = 0;
|
|
||||||
|
|
||||||
link->l_dest = object_ref(dest);
|
|
||||||
|
|
||||||
return link_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object *link_read_ptr(struct object *link_obj)
|
|
||||||
{
|
|
||||||
struct link *link = LINK_CAST(link_obj);
|
|
||||||
return link->l_dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool object_is_link(struct object *obj)
|
|
||||||
{
|
|
||||||
return obj->ob_type == &link_type;
|
|
||||||
}
|
|
||||||
334
obj/namespace.c
334
obj/namespace.c
@@ -1,334 +0,0 @@
|
|||||||
#include <mango/object.h>
|
|
||||||
|
|
||||||
#define NAMESPACE_CAST(p) OBJECT_C_CAST(struct object_namespace, ns_base, &ns_type, p)
|
|
||||||
|
|
||||||
static struct object_type ns_type;
|
|
||||||
static struct object_namespace *global_ns;
|
|
||||||
|
|
||||||
struct object_namespace {
|
|
||||||
/* root directory set object */
|
|
||||||
struct object ns_base;
|
|
||||||
struct object *ns_root;
|
|
||||||
};
|
|
||||||
|
|
||||||
static kern_status_t ns_query_name(struct object *obj, char out[OBJECT_NAME_MAX])
|
|
||||||
{
|
|
||||||
out[0] = '/';
|
|
||||||
out[1] = 0;
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static kern_status_t ns_get_child_at(struct object *obj, size_t at, struct object **out)
|
|
||||||
{
|
|
||||||
struct object_namespace *ns = NAMESPACE_CAST(obj);
|
|
||||||
return object_get_child_at(ns->ns_root, at, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static kern_status_t ns_get_child_named(struct object *obj, const char *name, struct object **out)
|
|
||||||
{
|
|
||||||
struct object_namespace *ns = NAMESPACE_CAST(obj);
|
|
||||||
return object_get_child_named(ns->ns_root, name, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct object_type ns_type = {
|
|
||||||
.ob_name = "namespace",
|
|
||||||
.ob_size = sizeof(struct object_namespace),
|
|
||||||
.ob_header_offset = offsetof(struct object_namespace, ns_base),
|
|
||||||
.ob_ops = {
|
|
||||||
.query_name = ns_query_name,
|
|
||||||
.get_named = ns_get_child_named,
|
|
||||||
.get_at = ns_get_child_at,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_global_namespace(void)
|
|
||||||
{
|
|
||||||
object_type_register(&ns_type);
|
|
||||||
global_ns = object_namespace_create();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object_namespace *global_namespace(void)
|
|
||||||
{
|
|
||||||
return global_ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object_namespace *object_namespace_create(void)
|
|
||||||
{
|
|
||||||
struct object *ns_object = object_create(&ns_type);
|
|
||||||
struct object_namespace *ns = NAMESPACE_CAST(ns_object);
|
|
||||||
ns->ns_root = set_create("/");
|
|
||||||
return ns;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cleanup_object_path(char *path, size_t len, size_t *parts)
|
|
||||||
{
|
|
||||||
while (path[len - 1] == '/') {
|
|
||||||
path[--len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t final_len = len;
|
|
||||||
*parts = 0;
|
|
||||||
|
|
||||||
int slashes = 0;
|
|
||||||
for (int i = 0; path[i]; i++) {
|
|
||||||
if (path[i] == '/') {
|
|
||||||
slashes++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slashes < 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *from = path + i;
|
|
||||||
char *to = path + i - slashes + 1;
|
|
||||||
int count = len - i;
|
|
||||||
memmove(to, from, count);
|
|
||||||
final_len -= (slashes - 1);
|
|
||||||
slashes = 0;
|
|
||||||
(*parts)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
path[final_len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object *ns_header(struct object_namespace *ns)
|
|
||||||
{
|
|
||||||
return &ns->ns_base;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_namespace_get_object(struct object_namespace *ns, const char *path, struct object **out)
|
|
||||||
{
|
|
||||||
if (*path != '/') {
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*path == '/') {
|
|
||||||
path++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t path_len = strlen(path);
|
|
||||||
if (path_len == 0) {
|
|
||||||
*out = object_ref(ns->ns_root);
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t parts = 0;
|
|
||||||
char *rpath = kmalloc(path_len + 1, 0);
|
|
||||||
if (!rpath) {
|
|
||||||
return KERN_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(rpath, path, path_len);
|
|
||||||
rpath[path_len] = 0;
|
|
||||||
cleanup_object_path(rpath, path_len, &parts);
|
|
||||||
|
|
||||||
char *sp;
|
|
||||||
char *tok = strtok_r(rpath, "/", &sp);
|
|
||||||
struct object *cur = ns->ns_root;
|
|
||||||
|
|
||||||
unsigned long flags;
|
|
||||||
while (tok) {
|
|
||||||
object_lock_irqsave(cur, &flags);
|
|
||||||
|
|
||||||
struct object *next;
|
|
||||||
kern_status_t status = object_get_child_named(cur, tok, &next);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
kfree(rpath);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
cur = next;
|
|
||||||
tok = strtok_r(NULL, "/", &sp);
|
|
||||||
|
|
||||||
object_lock_irqsave(cur, &flags);
|
|
||||||
if (!object_is_link(cur)) {
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object *dest_obj;
|
|
||||||
dest_obj = link_read_ptr(cur);
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
|
|
||||||
if (!dest_obj) {
|
|
||||||
kfree(rpath);
|
|
||||||
/* TODO better error code for broken links */
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_deref(cur);
|
|
||||||
cur = dest_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(rpath);
|
|
||||||
|
|
||||||
if (object_is_link(cur)) {
|
|
||||||
struct object *link_dest = link_read_ptr(cur);
|
|
||||||
object_deref(cur);
|
|
||||||
cur = object_ref(link_dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = cur;
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_namespace_create_link(struct object_namespace *ns, const char *linkpath, struct object *dest)
|
|
||||||
{
|
|
||||||
if (*linkpath != '/') {
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*linkpath == '/') {
|
|
||||||
linkpath++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t path_len = strlen(linkpath);
|
|
||||||
if (path_len == 0) {
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t parts = 0;
|
|
||||||
char *rpath = kmalloc(path_len + 1, 0);
|
|
||||||
if (!rpath) {
|
|
||||||
return KERN_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(rpath, linkpath, path_len);
|
|
||||||
rpath[path_len] = 0;
|
|
||||||
cleanup_object_path(rpath, path_len, &parts);
|
|
||||||
|
|
||||||
char *p = rpath + strlen(rpath) - 1;
|
|
||||||
while (*p != '/' && p >= rpath) {
|
|
||||||
p--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p == rpath) {
|
|
||||||
kfree(rpath);
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
*p = '\0';
|
|
||||||
const char *linkname = p + 1;
|
|
||||||
|
|
||||||
char *sp;
|
|
||||||
char *tok = strtok_r(rpath, "/", &sp);
|
|
||||||
struct object *cur = object_ref(ns->ns_root);
|
|
||||||
|
|
||||||
unsigned long flags;
|
|
||||||
while (tok) {
|
|
||||||
object_lock_irqsave(cur, &flags);
|
|
||||||
|
|
||||||
struct object *next;
|
|
||||||
kern_status_t status = object_get_child_named(cur, tok, &next);
|
|
||||||
if (status == KERN_NO_ENTRY) {
|
|
||||||
next = set_create(tok);
|
|
||||||
if (!next) {
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
object_deref(cur);
|
|
||||||
kfree(rpath);
|
|
||||||
return KERN_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = set_add_object(cur, next);
|
|
||||||
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
object_deref(cur);
|
|
||||||
} else {
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
kfree(rpath);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur = next;
|
|
||||||
tok = strtok_r(NULL, "/", &sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object *link = link_create(linkname, dest);
|
|
||||||
kfree(rpath);
|
|
||||||
|
|
||||||
if (!link) {
|
|
||||||
object_deref(cur);
|
|
||||||
return KERN_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_lock_irqsave(cur, &flags);
|
|
||||||
kern_status_t status = set_add_object(cur, link);
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
|
|
||||||
object_deref(cur);
|
|
||||||
object_deref(link);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj)
|
|
||||||
{
|
|
||||||
if (*path != '/') {
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*path == '/') {
|
|
||||||
path++;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t path_len = strlen(path);
|
|
||||||
if (path_len == 0) {
|
|
||||||
return set_add_object(ns->ns_root, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t parts = 0;
|
|
||||||
char *rpath = kmalloc(path_len, 0);
|
|
||||||
if (!rpath) {
|
|
||||||
return KERN_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(rpath, path, path_len);
|
|
||||||
cleanup_object_path(rpath, path_len, &parts);
|
|
||||||
|
|
||||||
char *sp;
|
|
||||||
char *tok = strtok_r(rpath, "/", &sp);
|
|
||||||
struct object *cur = ns->ns_root;
|
|
||||||
|
|
||||||
unsigned long flags;
|
|
||||||
while (tok) {
|
|
||||||
object_lock_irqsave(cur, &flags);
|
|
||||||
|
|
||||||
struct object *next;
|
|
||||||
kern_status_t status = object_get_child_named(cur, tok, &next);
|
|
||||||
if (status == KERN_NO_ENTRY) {
|
|
||||||
next = set_create(tok);
|
|
||||||
if (!next) {
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
kfree(rpath);
|
|
||||||
return KERN_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = set_add_object(cur, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
kfree(rpath);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
object_unlock_irqrestore(cur, flags);
|
|
||||||
cur = next;
|
|
||||||
tok = strtok_r(NULL, "/", &sp);
|
|
||||||
}
|
|
||||||
|
|
||||||
kfree(rpath);
|
|
||||||
|
|
||||||
return set_add_object(cur, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t object_unpublish(struct object_namespace *ns, struct object *obj)
|
|
||||||
{
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
134
obj/set.c
134
obj/set.c
@@ -1,134 +0,0 @@
|
|||||||
#include <mango/object.h>
|
|
||||||
|
|
||||||
#define SET_CAST(p) OBJECT_C_CAST(struct set, s_base, &set_type, p)
|
|
||||||
|
|
||||||
struct set {
|
|
||||||
struct object s_base;
|
|
||||||
struct queue s_list;
|
|
||||||
char s_name[OBJECT_NAME_MAX];
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct object_type set_type;
|
|
||||||
|
|
||||||
static kern_status_t set_query_name(struct object *obj, char out[OBJECT_NAME_MAX])
|
|
||||||
{
|
|
||||||
struct set *set = SET_CAST(obj);
|
|
||||||
strncpy(out, set->s_name, OBJECT_NAME_MAX - 1);
|
|
||||||
out[OBJECT_NAME_MAX - 1] = 0;
|
|
||||||
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static kern_status_t set_get_child_at(struct object *obj, size_t at, struct object **out)
|
|
||||||
{
|
|
||||||
struct set *set = SET_CAST(obj);
|
|
||||||
size_t i = 0;
|
|
||||||
queue_foreach(struct object, child, &set->s_list, ob_list) {
|
|
||||||
if (i == at) {
|
|
||||||
*out = object_ref(child);
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return KERN_NO_ENTRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
static kern_status_t set_get_child_named(struct object *obj, const char *name, struct object **out)
|
|
||||||
{
|
|
||||||
struct set *set = SET_CAST(obj);
|
|
||||||
char child_name[OBJECT_NAME_MAX];
|
|
||||||
|
|
||||||
queue_foreach(struct object, child, &set->s_list, ob_list) {
|
|
||||||
kern_status_t status = object_query_name(child, child_name);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(child_name, name)) {
|
|
||||||
*out = object_ref(child);
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return KERN_NO_ENTRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct object_type set_type = {
|
|
||||||
.ob_name = "set",
|
|
||||||
.ob_size = sizeof(struct set),
|
|
||||||
.ob_header_offset = offsetof(struct set, s_base),
|
|
||||||
.ob_ops = {
|
|
||||||
.query_name = set_query_name,
|
|
||||||
.get_named = set_get_child_named,
|
|
||||||
.get_at = set_get_child_at,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
void init_set_objects(void)
|
|
||||||
{
|
|
||||||
object_type_register(&set_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct object *set_create(const char *name)
|
|
||||||
{
|
|
||||||
struct object *set_obj = object_create(&set_type);
|
|
||||||
if (!set_obj) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct set *set = SET_CAST(set_obj);
|
|
||||||
set->s_list = QUEUE_INIT;
|
|
||||||
strncpy(set->s_name, name, sizeof set->s_name - 1);
|
|
||||||
set->s_name[sizeof set->s_name - 1] = 0;
|
|
||||||
|
|
||||||
return set_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t set_add_object(struct object *set_obj, struct object *obj)
|
|
||||||
{
|
|
||||||
if (!object_is_set(set_obj)) {
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct set *set = SET_CAST(set_obj);
|
|
||||||
|
|
||||||
char child_name[OBJECT_NAME_MAX];
|
|
||||||
char obj_name[OBJECT_NAME_MAX];
|
|
||||||
|
|
||||||
kern_status_t status = object_query_name(obj, obj_name);
|
|
||||||
if (status != KERN_OK) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
queue_foreach (struct object, child, &set->s_list, ob_list) {
|
|
||||||
object_query_name(child, child_name);
|
|
||||||
|
|
||||||
if (!strcmp(child_name, obj_name)) {
|
|
||||||
return KERN_NAME_EXISTS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object_ref(obj);
|
|
||||||
queue_push_back(&set->s_list, &obj->ob_list);
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
kern_status_t set_remove_object(struct object *set_obj, struct object *obj)
|
|
||||||
{
|
|
||||||
if (!object_is_set(set_obj)) {
|
|
||||||
return KERN_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct set *set = SET_CAST(set_obj);
|
|
||||||
queue_delete(&set->s_list, &obj->ob_list);
|
|
||||||
object_deref(obj);
|
|
||||||
|
|
||||||
return KERN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool object_is_set(struct object *obj)
|
|
||||||
{
|
|
||||||
return obj->ob_type == &set_type;
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(magenta-tools C)
|
project(mango-tools C)
|
||||||
|
|
||||||
set(tool_dirs e64patch)
|
set(tool_dirs e64patch)
|
||||||
|
|
||||||
|
|||||||
@@ -7,24 +7,27 @@ shift 2
|
|||||||
if command -v gdb &> /dev/null; then
|
if command -v gdb &> /dev/null; then
|
||||||
printf " \033[93;1mGDB\033[0m boot/mango_kernel\n"
|
printf " \033[93;1mGDB\033[0m boot/mango_kernel\n"
|
||||||
tmux \
|
tmux \
|
||||||
new-session -d -s hz-debug "sleep 0.3; gdb -tui -x $gdb_cfg" \; \
|
new-session -d -s mango-debug "sleep 0.3; gdb -tui -x $gdb_cfg" \; \
|
||||||
split-window -h -l 80 \; \
|
split-window -h -l 80 \; \
|
||||||
split-window -v -l 25 "$@"\; \
|
split-window -v -l 25 "$@"\; \
|
||||||
select-pane -t 1 \; \
|
select-pane -t 1 \; \
|
||||||
resize-pane -R 20
|
resize-pane -R 20 \; \
|
||||||
|
select-pane -t 0
|
||||||
|
|
||||||
elif command -v lldb &> /dev/null; then
|
elif command -v lldb &> /dev/null; then
|
||||||
printf " \033[93;1mLLDB\033[0m boot/mango_kernel\n"
|
printf " \033[93;1mLLDB\033[0m boot/mango_kernel\n"
|
||||||
tmux \
|
tmux \
|
||||||
new-session -d -s hz-debug "sleep 0.1; lldb --source $lldb_cfg" \; \
|
new-session -d -s mango-debug "sleep 0.1; lldb --source $lldb_cfg" \; \
|
||||||
split-window -h -l 160 \; \
|
split-window -h -l 160 \; \
|
||||||
split-window -v -l 25 "$@"\; \
|
split-window -v -l 25 "$@"\; \
|
||||||
select-pane -t 1 \; \
|
select-pane -t 1 \; \
|
||||||
resize-pane -R 50
|
resize-pane -R 50 \; \
|
||||||
|
select-pane -t 0
|
||||||
else
|
else
|
||||||
printf " \033[91;1mERR\033[0m No debugger available\n"
|
printf " \033[91;1mERR\033[0m No debugger available\n"
|
||||||
exit -1
|
exit -1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tmux a -t hz-debug
|
tmux a -t mango-debug
|
||||||
tmux kill-session -t hz-debug
|
tmux kill-session -t mango-debug
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
set confirm off
|
set confirm off
|
||||||
symbol-file build/mango_kernel.dbg
|
symbol-file mango_kernel.debug
|
||||||
target remote localhost:1234
|
target remote localhost:1234
|
||||||
set confirm on
|
set confirm on
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
file build/mango_kernel.dbg
|
file mango_kernel.debug
|
||||||
gdb-remote localhost:1234
|
gdb-remote localhost:1234
|
||||||
|
|||||||
Reference in New Issue
Block a user