[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH] kernel2: Virtuell, aber nicht physisch zusammenhaengender Speicher
+ kernel2: mmc_valloc() alloziert virtuell zusammenhaengenden Speicher,
der aber physisch nicht zusammenhaengend sein muss
! kernel2: Entsprechende FIXMEs geloest, wo bisher unnoetigerweise
physisch zusammenhaengender Speicher reserviert wurde
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/kernel2/include/mm.h | 32 ++++++++++++++
src/kernel2/src/arch/i386/mm/mm_context.c | 64 +++++++++++++++++++++++++++++
src/kernel2/src/mm/shm.c | 34 +++++++++++----
src/kernel2/src/syscalls/mem.c | 17 ++++----
src/kernel2/src/syscalls/pm.c | 6 +--
5 files changed, 131 insertions(+), 22 deletions(-)
diff --git a/src/kernel2/include/mm.h b/src/kernel2/include/mm.h
index e143fb7..0144aca 100644
--- a/src/kernel2/include/mm.h
+++ b/src/kernel2/include/mm.h
@@ -74,6 +74,9 @@ void vmm_kernel_unmap(vaddr_t start, size_t size);
/*
* MM-Kontext
+ *
+ * FIXME Den ganzen generischen Funktionen i386-spezifische Flags zu geben, ist
+ * moeglicherweise keine gute Idee...
*/
mmc_context_t mmc_create(void);
@@ -93,6 +96,35 @@ vaddr_t mmc_automap_user(mmc_context_t* target_ctx, mmc_context_t* source_ctx,
vaddr_t start, size_t count, uintptr_t lower_limit, uintptr_t upper_limit,
int flags);
+/**
+ * Alloziert einen virtuell (aber nicht zwingend physisch) zusammenhaengenden
+ * Speicherbereich
+ *
+ * @param context Speicherkontext, in den die Seiten gemappt werden sollen
+ * @param num_pages Anzahl der zu mappenden Seiten
+ * @param phys_lower_limit Niedrigste zulaessige physische Adresse
+ * @param phys_upper_limit Hoechste zulaessige physische Adresse. Wenn der Wert
+ * NULL ist, werden die zulaessigen physischen Adressen nicht eingeschraenkt.
+ * @param virt_lower_limit Niedrigste zulaessige virtuelle Adresse
+ * @param virt_upper_limit Hoechste zulaessige virtuelle Adresse
+ * @param flags Flags fuer die Pagetable
+ */
+vaddr_t mmc_valloc_limits(mmc_context_t* context, size_t num_pages,
+ paddr_t phys_lower_limit, paddr_t phys_upper_limit,
+ uintptr_t virt_lower_limit, uintptr_t virt_upper_limit, int flags);
+
+/**
+ * Alloziert einen virtuell (aber nicht zwingend physisch) zusammenhaengenden
+ * Speicherbereich. Dies ist eine abkuerzende Variante von mmc_valloc_limits,
+ * die die Standardlimits fuer User- bzw. Kernelspace benutzt, je nachdem ob
+ * PTE_U in den Flags gesetzt ist oder nicht.
+ *
+ * @param context Speicherkontext, in den die Seiten gemappt werden sollen
+ * @param num_pages Anzahl der zu mappenden Seiten
+ * @param flags Flags fuer die Pagetable
+ */
+vaddr_t mmc_valloc(mmc_context_t* context, size_t num_pages, int flags);
+
void mmc_activate(mmc_context_t* context);
#define mmc_current_context() (*cpu_get_current()->mm_context)
diff --git a/src/kernel2/src/arch/i386/mm/mm_context.c b/src/kernel2/src/arch/i386/mm/mm_context.c
index 722d052..34ac946 100644
--- a/src/kernel2/src/arch/i386/mm/mm_context.c
+++ b/src/kernel2/src/arch/i386/mm/mm_context.c
@@ -574,3 +574,67 @@ vaddr_t mmc_automap_user(mmc_context_t* target_ctx, mmc_context_t* source_ctx,
return free_page;
}
+
+/**
+ * Alloziert einen virtuell (aber nicht zwingend physisch) zusammenhaengenden
+ * Speicherbereich
+ *
+ * @param context Speicherkontext, in den die Seiten gemappt werden sollen
+ * @param num_pages Anzahl der zu mappenden Seiten
+ * @param phys_lower_limit Niedrigste zulaessige physische Adresse
+ * @param phys_upper_limit Hoechste zulaessige physische Adresse. Wenn der Wert
+ * NULL ist, werden die zulaessigen physischen Adressen nicht eingeschraenkt.
+ * @param virt_lower_limit Niedrigste zulaessige virtuelle Adresse
+ * @param virt_upper_limit Hoechste zulaessige virtuelle Adresse
+ * @param flags Flags fuer die Pagetable
+ */
+inline vaddr_t mmc_valloc_limits(mmc_context_t* context, size_t num_pages,
+ paddr_t phys_lower_limit, paddr_t phys_upper_limit,
+ uintptr_t virt_lower_limit, uintptr_t virt_upper_limit, int flags)
+{
+ size_t i;
+ paddr_t paddr;
+ vaddr_t vaddr;
+ vaddr_t free_page = find_contiguous_pages(context, num_pages,
+ virt_lower_limit, virt_upper_limit);
+
+ if (free_page == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < num_pages; i++) {
+ if (!phys_upper_limit) {
+ paddr = pmm_alloc(1);
+ } else {
+ paddr = pmm_alloc_limits(phys_lower_limit, phys_upper_limit, 1);
+ }
+ vaddr = free_page + (i * PAGE_SIZE);
+ if (!mmc_map(context, vaddr, paddr, flags, 1)) {
+ mmc_unmap(context, free_page, i);
+ return NULL;
+ }
+ }
+
+ return free_page;
+}
+
+/**
+ * Alloziert einen virtuell (aber nicht zwingend physisch) zusammenhaengenden
+ * Speicherbereich. Dies ist eine abkuerzende Variante von mmc_valloc_limits,
+ * die die Standardlimits fuer User- bzw. Kernelspace benutzt, je nachdem ob
+ * PTE_U in den Flags gesetzt ist oder nicht.
+ *
+ * @param context Speicherkontext, in den die Seiten gemappt werden sollen
+ * @param num_pages Anzahl der zu mappenden Seiten
+ * @param flags Flags fuer die Pagetable
+ */
+vaddr_t mmc_valloc(mmc_context_t* context, size_t num_pages, int flags)
+{
+ if (flags & PTE_U) {
+ return mmc_valloc_limits(context, num_pages, NULL, NULL,
+ MM_USER_START, MM_USER_END, flags);
+ } else {
+ return mmc_valloc_limits(context, num_pages, NULL, NULL,
+ KERNEL_MEM_START, KERNEL_MEM_END, flags);
+ }
+}
diff --git a/src/kernel2/src/mm/shm.c b/src/kernel2/src/mm/shm.c
index 72c5eac..67b4831 100644
--- a/src/kernel2/src/mm/shm.c
+++ b/src/kernel2/src/mm/shm.c
@@ -46,7 +46,6 @@ struct shm_desc {
uint64_t id;
struct tree_item tree_item;
- paddr_t paddr;
size_t num_pages;
list_t* processes;
};
@@ -75,8 +74,6 @@ void shm_init(void)
*/
uint32_t shm_create(size_t size)
{
- // FIXME Die Pages muessen nicht physisch zusammenhaengend sein
- paddr_t shm_phys = pmm_alloc(NUM_PAGES(size));
uint32_t id = ++shm_last_id;
struct shm_desc* shm;
@@ -87,7 +84,6 @@ uint32_t shm_create(size_t size)
shm = calloc(1, sizeof(*shm));
shm->id = id;
shm->num_pages = NUM_PAGES(size);
- shm->paddr = shm_phys;
shm->processes = list_create();
tree_insert(shms, shm);
@@ -112,8 +108,17 @@ void* shm_attach(uint32_t id)
return NULL;
}
- ret = mmc_automap(&mmc_current_context(), shm->paddr, shm->num_pages,
- MM_USER_START, MM_USER_END, MM_FLAGS_USER_DATA);
+ if (list_is_empty(shm->processes)) {
+ // Erster Prozess, der den SHM oeffnet: Speicher allozieren
+ ret = mmc_valloc(&mmc_current_context(), shm->num_pages,
+ MM_FLAGS_USER_DATA);
+ } else {
+ // Ansonsten Mapping von einem anderen Prozess uebernehmen
+ struct shm_process* first = list_get_element_at(shm->processes, 0);
+ ret = mmc_automap_user(&mmc_current_context(),
+ &first->process->context, first->vaddr, shm->num_pages,
+ MM_USER_START, MM_USER_END, MM_FLAGS_USER_DATA);
+ }
if (ret == NULL) {
return NULL;
@@ -155,13 +160,24 @@ void shm_detach(uint32_t id)
found:
- mmc_unmap(&mmc_current_context(), shm_proc->vaddr, shm->num_pages);
-
// Wenn es der letzte Benutzer war, SHM loeschen
if (list_is_empty(shm->processes)) {
+ for (i = 0; i < shm->num_pages; i++) {
+ pmm_free(mmc_resolve(&mmc_current_context(),
+ shm_proc->vaddr + (i * PAGE_SIZE)), 1);
+ }
+
list_destroy(shm->processes);
- pmm_free(shm->paddr, shm->num_pages);
+ shm->processes = NULL;
tree_remove(shms, shm);
+ }
+
+ // Virtuellen Speicher freigeben
+ mmc_unmap(&mmc_current_context(), shm_proc->vaddr, shm->num_pages);
+
+
+ free(shm_proc);
+ if (shm->processes == NULL) {
free(shm);
}
diff --git a/src/kernel2/src/syscalls/mem.c b/src/kernel2/src/syscalls/mem.c
index 91457da..ff66fa0 100644
--- a/src/kernel2/src/syscalls/mem.c
+++ b/src/kernel2/src/syscalls/mem.c
@@ -54,20 +54,19 @@ vaddr_t syscall_mem_allocate(size_t bytes, syscall_arg_t flags, paddr_t* phys)
vaddr_t address = NULL;
size_t page_count = NUM_PAGES(PAGE_ALIGN_ROUND_UP(bytes));
- // Der Speicher muss nicht physisch zusamenhaengend sein.
if (flags & 0x80) {
+ // ISA-DMA-Speicher
+ // Physisch zusammenhaengend und nur in den ersten 16 MB
+ // FIXME Eigentlich muesste man hier auf 64k-Grenzen aufpassen
*phys = pmm_alloc_limits((paddr_t) 0, (paddr_t) (16 * 1024 * 1024),
page_count);
+ address = mmc_automap(&mmc_current_context(), *phys, page_count,
+ USER_MEM_START, USER_MEM_END, MM_FLAGS_USER_DATA);
} else {
- *phys = pmm_alloc(page_count);
- }
-
- address = mmc_automap(&mmc_current_context(), *phys, page_count,
- USER_MEM_START, USER_MEM_END, MM_FLAGS_USER_DATA);
-
- // Die physische Adresse gibt es nur fuer DMA
- if ((flags & 0x80) == 0) {
+ // Normaler Speicher, muss nicht zusammenhaengend sein
*phys = 0;
+ address = mmc_valloc(&mmc_current_context(), page_count,
+ MM_FLAGS_USER_DATA);
}
return address;
diff --git a/src/kernel2/src/syscalls/pm.c b/src/kernel2/src/syscalls/pm.c
index 750d3dc..df99961 100644
--- a/src/kernel2/src/syscalls/pm.c
+++ b/src/kernel2/src/syscalls/pm.c
@@ -262,10 +262,8 @@ void* syscall_pm_enumerate_tasks(void)
// Jetzt wird eine freie Stelle im Adressraum des Prozesses
// gesucht, wo die Task-Infos hingemappt werden koennen
- // FIXME Die Seiten muessen nicht physisch zusammenhaengend sein
- task_info_t* task_info = mmc_automap(&mmc_current_context(),
- pmm_alloc(result_page_count), result_page_count, MM_USER_START,
- MM_USER_END, PTE_P | PTE_W | PTE_U);
+ task_info_t* task_info = mmc_valloc(&mmc_current_context(),
+ result_page_count, MM_FLAGS_USER_DATA);
// Der Groessen-Eintrag ist nur da, damit der Task die Pages
// freigeben koennte.
--
1.6.0.2