diff options
| author | Alejandro Sior <aho@sior.be> | 2022-07-26 14:06:40 +0200 |
|---|---|---|
| committer | Alejandro Sior <aho@sior.be> | 2022-07-26 14:06:40 +0200 |
| commit | e0fbf5ca9599cb7599731fe48573e97d05fa38da (patch) | |
| tree | 2c3b3925c49fd2da68086c6cb4b06a891e823bd5 | |
| parent | c4e9a8ba15391ae5f1c820744ff1b03544d63467 (diff) | |
mem/vmap: add basic virtual memory management abstraction
| -rw-r--r-- | arch/amd64/mem/meson.build | 7 | ||||
| -rw-r--r-- | arch/amd64/mem/vmap.c | 2 | ||||
| -rw-r--r-- | arch/amd64/mem/vmap.h | 12 | ||||
| -rw-r--r-- | arch/amd64/meson.build | 15 | ||||
| -rw-r--r-- | mem/docs/allocator.9.scd | 4 | ||||
| -rw-r--r-- | mem/docs/framer.9.scd | 4 | ||||
| -rw-r--r-- | mem/docs/vmap.9.scd | 80 | ||||
| -rw-r--r-- | mem/errors.h | 12 | ||||
| -rw-r--r-- | mem/framer.c | 8 | ||||
| -rw-r--r-- | mem/framer.h | 4 | ||||
| -rw-r--r-- | mem/meson.build | 3 | ||||
| -rw-r--r-- | mem/vmap.c | 26 | ||||
| -rw-r--r-- | mem/vmap.h | 31 |
13 files changed, 193 insertions, 15 deletions
diff --git a/arch/amd64/mem/meson.build b/arch/amd64/mem/meson.build new file mode 100644 index 0000000..1e26a72 --- /dev/null +++ b/arch/amd64/mem/meson.build @@ -0,0 +1,7 @@ +amd64_mem_src = [ + 'vmap.c' +] + +amd64_mem = static_library('amd64_mem', amd64_mem_src, include_directories: amd64_inc) + +amd64_mod += amd64_mem
\ No newline at end of file diff --git a/arch/amd64/mem/vmap.c b/arch/amd64/mem/vmap.c new file mode 100644 index 0000000..6bb786c --- /dev/null +++ b/arch/amd64/mem/vmap.c @@ -0,0 +1,2 @@ +#include "vmap.h" + diff --git a/arch/amd64/mem/vmap.h b/arch/amd64/mem/vmap.h new file mode 100644 index 0000000..c13b887 --- /dev/null +++ b/arch/amd64/mem/vmap.h @@ -0,0 +1,12 @@ +#ifndef AMD64_MEM_VMAP_H +#define AMD64_MEM_VMAP_H + +#include <mem/vmap.h> + +typedef struct amd64_mem_vmap { + MemVmap vmap; + + +} Amd64MemVmap; + +#endif
\ No newline at end of file diff --git a/arch/amd64/meson.build b/arch/amd64/meson.build index 4c64c8c..03e574c 100644 --- a/arch/amd64/meson.build +++ b/arch/amd64/meson.build @@ -1,13 +1,18 @@ -amd64_src = [ - 'quirks.c' -] - amd64_linker_sc = meson.current_source_dir() / 'linker.sc' kernel_link_dep += amd64_linker_sc kernel_link_arg += '-T' + amd64_linker_sc kernel_inc += include_directories('include') -amd64 = static_library('amd64', amd64_src, include_directories: kernel_inc) +amd64_src = [ + 'quirks.c' +] +amd64_inc = kernel_inc +amd64_mod = [] + +# Modules +subdir('mem') + +amd64 = static_library('amd64', amd64_src, link_with: amd64_mod, include_directories: kernel_inc) kernel_mod += amd64
\ No newline at end of file diff --git a/mem/docs/allocator.9.scd b/mem/docs/allocator.9.scd index df708a7..c70156a 100644 --- a/mem/docs/allocator.9.scd +++ b/mem/docs/allocator.9.scd @@ -1,4 +1,4 @@ -MEMALLOCATOR(9) +MEM_ALLOCATOR(9) # NAME @@ -65,4 +65,4 @@ The MemAllocator interface and its dispatching functions are implemented in _mem # SEE ALSO -memframer(9)
\ No newline at end of file +mem_framer(9)
\ No newline at end of file diff --git a/mem/docs/framer.9.scd b/mem/docs/framer.9.scd index 5836e19..1bc3670 100644 --- a/mem/docs/framer.9.scd +++ b/mem/docs/framer.9.scd @@ -1,4 +1,4 @@ -MEMFRAMER(9) +MEM_FRAMER(9) # NAME @@ -18,7 +18,7 @@ void mem_framer_free(MemAllocator *self, void *ptr); # DESCRIPTION -*MemFramer* and its related functions is an implementation of memallocator(9) designed to manage the allocation and freeing of chunks of same size - they are called _frames_ - that are boundary aligned on multiples of that size. +*MemFramer* and its related functions is an implementation of mem_allocator(9) designed to manage the allocation and freeing of chunks of same size - they are called _frames_ - that are boundary aligned on multiples of that size. *MemFramer* is a linked-list allocator, meaning that when a frame is requested, it can either pop the frame from a free list (a linked list of frames that have previously been freed), or bump a new frame from the region of usable memory that it manages. diff --git a/mem/docs/vmap.9.scd b/mem/docs/vmap.9.scd new file mode 100644 index 0000000..89faca7 --- /dev/null +++ b/mem/docs/vmap.9.scd @@ -0,0 +1,80 @@ +MEM_VMAP(9) + +# NAME + +*mem_vmap_translate*, *mem_vmap_map*, *mem_vmap_unmap* - manage virtual address spaces + +# SYNOPSIS + +``` +#include <mem/vmap.h> + +typedef struct mem_vmap MemVmap; + +usize mem_vmap_translate(MemVmap *inner, usize virt); +int mem_vmap_map(MemVmap *inner, usize phys, usize virt, usize len, int flags); +void mem_vmap_unmap(MemVmap *inner, usize virt, usize len); +``` + +# DESCRIPTION + +Many CPUs offer the ability to specify mappings between what the CPU regular memory accesses can see, and the physical memory as laid by the machine. A set of mappings enabled at once at the same time is said to constitute a *virtual address space*, in that it is the space of addresses that are meaningful to the current execution environment of the CPU. + +*MemVmap* and its related utility methods are an abstraction over the hardware's memory mapping facilities to allow managing an address space and switch from an address space to another. + +## Translation + +Translation is the action of taking a virtual address and obtaining its physical address. A CPU supporting memory mapping can do this relatively efficiently compared with simulating it in software. + +The *mem_vmap_translate()* function translates a virtual address into its physical one in software. This can be useful for a few reasons and this mechanism is used internally by MemVmap implementation themselves. *mem_vmap_translate()* takes the following arguments: + + _inner_ The *MemVmap* to use + _virt_ The virtual address to translate + +If the translation lands on an unmapped region of the virtual address space, the miss flag is set. + +## Mapping + +The *mem_vmap_map()* function maps a region of physical memory into the specified virtual address space, around a specified virtual address, with some flags. *mem_vmap_map()* takes the following arguments: + + _inner_ The *MemVmap* to use + _phys_ The beginning of the physical memory region that will back the map + _virt_ The beginning of the virtual memory region to which the physical memory shall be mapped + _len_ The length of the region in char-sized units + _flags_ The flags with which the region must be mapped + +The mapping operation may fail for reasons, such as: + - The requested mapping overlaps with a pre-existing mapping + +## Unmapping + +Unmapping is the inverse operation of mapping, it removes a particular map from the set of mappings. + +The *mem_vmap_unmap()* function is used to perform the unmap operation on a particular address space at a specified virtual address. *mem_vmap_unmap()* takes the following arguments: + + _inner_ The *MemVmap* to use + _virt_ The beginning of the virtual memory region that must be unmapped + _len_ The length of the virtual memory region that must be unmapped + +Note: it is not an error to unmap a region of virtual memory that is not already mapped. The unmap operation, if properly implemented, should not fail. + +# Switching + +The *mem_vmap_switch_to()* functions is used to enable a particular address space. It takes only one argument, _inner_ the address space to switch to. + +Note: the caller should naturally make sure that the current code being executed, along with the required data, is correctly mapped at the according places in the target address space. + +# FLAGS + +XXX todo, unimplemented yet + +# RETURN VALUES + +*mem_vmap_translate()* returns a physical address on success, 0 in case of error or miss +*mem_vmap_map()* returns 0 in case of success, or a non-zero value in case of error + +Refer to mem/errors.h for the list of error codes pertaining to the _mem_ module + +# CODE REFERENCES + +*MemVmap* and its related functions are defined in _mem/vmap.c_. Also refer to its particular implementations.
\ No newline at end of file diff --git a/mem/errors.h b/mem/errors.h new file mode 100644 index 0000000..e926214 --- /dev/null +++ b/mem/errors.h @@ -0,0 +1,12 @@ +#ifndef MEM_ERRORS_H +#define MEM_ERRORS_H + +enum mem_error { + MEM_OK = 0, + + /* Returned when an implementation does not support + one of the vmap operations */ + MEM_VMAP_UNSUPPORTED +}; + +#endif
\ No newline at end of file diff --git a/mem/framer.c b/mem/framer.c index 9a66feb..dbd8c9a 100644 --- a/mem/framer.c +++ b/mem/framer.c @@ -23,9 +23,9 @@ MemFramer *mem_framer_install(void *addr, usize end, uint blksz) { void *mem_framer_alloc(MemAllocator *inner, usize n) { /* When allocating a frame, we have two paths: 1. The freelist is not empty: give away - the last freed frame - 2. The freelist is empty: bump away the next - frame (pointed at by the next member) + the last freed frame + 2. The freelist is empty: bump away the next + frame (pointed at by the next member) The alloc must fail the freelist is empty and that the next is beyond the end of the region */ @@ -53,7 +53,7 @@ void *mem_framer_alloc(MemAllocator *inner, usize n) { void mem_framer_free(MemAllocator *inner, void *ptr) { /* NOTE: this implementation does make the assumption that the given pointer is the base of the allocated - region without correction */ + region without correction */ MemFramer *self = (MemFramer*)inner; diff --git a/mem/framer.h b/mem/framer.h index 6d7034b..e2a6945 100644 --- a/mem/framer.h +++ b/mem/framer.h @@ -5,6 +5,8 @@ #include "allocator.h" +/* Represents a free frame as part of the freelist, this is done + in order to avoid having to do annoying casts */ typedef struct mem_framer_freed { struct mem_framer_freed *next; } MemFramerFreed; @@ -24,7 +26,7 @@ typedef struct mem_framer { the freelist NOTE: the freelist is a singly-linked list comprising all frames that have been previously allocated - and then freed */ + and then freed */ MemFramerFreed *free; /* The size of a frame. This value also defines the alignment diff --git a/mem/meson.build b/mem/meson.build index ec4a984..e4db123 100644 --- a/mem/meson.build +++ b/mem/meson.build @@ -1,6 +1,7 @@ mem_src = [ 'allocator.c', - 'framer.c' + 'framer.c', + 'vmap.c' ] mem = static_library('mem', mem_src, include_directories: kernel_inc) diff --git a/mem/vmap.c b/mem/vmap.c new file mode 100644 index 0000000..618b19e --- /dev/null +++ b/mem/vmap.c @@ -0,0 +1,26 @@ +#include "vmap.h" +#include "errors.h" + +usize mem_vmap_translate(MemVmap *inner, usize virt) { + if (inner->translate) + return inner->translate(inner, virt); + + return 0; +} + +int mem_vmap_map(MemVmap *inner, usize phys, usize virt, usize len, int flags) { + if (inner->map) + return inner->map(inner, phys, virt, len, flags); + + return MEM_VMAP_UNSUPPORTED; +} + +void mem_vmap_unmap(MemVmap *inner, usize virt, usize len) { + if (inner->unmap) + inner->unmap(inner, virt, len); +} + +void mem_vmap_switch_to(MemVmap *inner) { + if (inner->switch_to) + inner->switch_to(inner); +}
\ No newline at end of file diff --git a/mem/vmap.h b/mem/vmap.h new file mode 100644 index 0000000..4e1816c --- /dev/null +++ b/mem/vmap.h @@ -0,0 +1,31 @@ +#ifndef MEM_VMAP_H +#define MEM_VMAP_H + +#include <rt.h> + +typedef struct mem_vmap MemVmap; + +typedef usize (*MemVmapTranslate)(MemVmap *, usize); +typedef int (*MemVmapMap)(MemVmap *, usize, usize, usize, int); +typedef int (*MemVmapUnmap)(MemVmap *, usize, usize); +typedef void (*MemVmapSwitchTo)(MemVmap *); + +/* Structure abstracting the memory mapping facilities of + the machine */ +struct mem_vmap { + MemVmapTranslate translate; + MemVmapMap map; + MemVmapUnmap unmap; + MemVmapSwitchTo switch_to; + + /* Flag indicating whether the previous translation + lead to a miss */ + int miss; +}; + +usize mem_vmap_translate(MemVmap *inner, usize virt); +int mem_vmap_map(MemVmap *inner, usize phys, usize virt, usize len, int flags); +void mem_vmap_unmap(MemVmap *inner, usize virt, usize len); +void mem_vmap_switch_to(MemVmap *inner); + +#endif
\ No newline at end of file |
