summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--kernel/user.c60
1 files changed, 41 insertions, 19 deletions
diff --git a/kernel/user.c b/kernel/user.c
index b4f10d5..9d933e5 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -13,43 +13,61 @@
#define USER_STACK_TOP 0x800000000000
#define USER_STACK_LEN (4 * PAGE_SIZE)
+#define BLOCK_SIZE (PAGE_SIZE * 1000)
+static uint8_t *load_buffer = NULL;
+
static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx)
{
- uint8_t buf[PAGE_SIZE];
Elf64_Phdr hdr;
- size_t npages, nvpages, nbytes;
+ size_t mem_bytes, mem_pages;
+ size_t file_bytes, file_pages;
+ uint8_t *mapADDR;
hdr = pcb->elf_segments[idx];
- nbytes = hdr.p_filesz;
- npages = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE;
- nvpages = (hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE;
- if (npages < 1)
+ // return if this is not a lodable segment
+ if (hdr.p_type != PT_LOAD)
return 0;
- if (hdr.p_type != PT_LOAD)
+ mem_bytes = hdr.p_memsz;
+ file_bytes = hdr.p_filesz;
+
+ // we cannot read more data to less memory
+ if (file_bytes > mem_bytes)
+ return 1;
+
+ mem_pages = (mem_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+ file_pages = (file_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+
+ // return if were reading no data
+ if (file_pages < 1)
return 0;
// allocate memory in user process
- if (mem_alloc_pages_at(pcb->memctx, nvpages, (void *)hdr.p_vaddr,
+ if (mem_alloc_pages_at(pcb->memctx, mem_pages, (void *)hdr.p_vaddr,
F_WRITEABLE | F_UNPRIVILEGED) == NULL)
return 1;
+ mapADDR = kmapuseraddr(pcb->memctx, (void *)hdr.p_vaddr, mem_bytes);
+ if (mapADDR == NULL)
+ return 1;
+
// load data
- for (size_t i = 0; i < npages && nbytes; i++) {
- size_t bytes = PAGE_SIZE;
- if (nbytes < bytes)
- bytes = nbytes;
- mem_ctx_switch(kernel_mem_ctx); // disk_read is kernel internal
- memset(buf + bytes, 0, PAGE_SIZE - bytes);
- if (disk_read(disk, hdr.p_offset + i * PAGE_SIZE, bytes, buf))
+ size_t total_read = 0;
+ while (total_read < file_bytes) {
+ size_t read = BLOCK_SIZE;
+ if (read > file_bytes - total_read)
+ read = file_bytes - total_read;
+ if ((read = disk_read(disk, hdr.p_offset + total_read, read,
+ load_buffer)) < 1) {
+ kunmapaddr(mapADDR);
return 1;
- mem_ctx_switch(pcb->memctx);
- memcpy((char *)hdr.p_vaddr + i * PAGE_SIZE, buf, bytes);
- nbytes -= bytes;
+ }
+ memcpyv(mapADDR + total_read, load_buffer, read);
+ total_read += read;
}
- mem_ctx_switch(kernel_mem_ctx);
+ kunmapaddr(mapADDR);
return 0;
}
@@ -57,6 +75,10 @@ static int user_load_segments(struct pcb *pcb, struct disk *disk)
{
int ret = 0;
+ if (load_buffer == NULL)
+ if ((load_buffer = kalloc(BLOCK_SIZE)) == NULL)
+ return 1;
+
for (int i = 0; i < pcb->n_elf_segments; i++)
if ((ret = user_load_segment(pcb, disk, i)))
return ret;