diff options
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | include/asm/io.h | 4 | ||||
| -rw-r--r-- | include/asm/system.h | 3 | ||||
| -rw-r--r-- | include/kernel/memory.h | 18 | ||||
| -rw-r--r-- | include/kernel/sched.h | 26 | ||||
| -rw-r--r-- | include/string.h | 37 | ||||
| -rw-r--r-- | kernel/Makefile | 2 | ||||
| -rw-r--r-- | kernel/asm.s | 60 | ||||
| -rw-r--r-- | kernel/boot.s | 4 | ||||
| -rw-r--r-- | kernel/kmain.c | 5 | ||||
| -rw-r--r-- | kernel/memory.c | 129 | ||||
| -rw-r--r-- | kernel/page.s | 55 | ||||
| -rw-r--r-- | kernel/sched.c | 131 | ||||
| -rw-r--r-- | kernel/usrspace.s | 45 | ||||
| -rw-r--r-- | lib/Makefile | 29 | ||||
| -rw-r--r-- | lib/string.c | 173 | ||||
| -rw-r--r-- | usrbin/Makefile | 7 | ||||
| -rw-r--r-- | usrbin/link.ld | 2 |
18 files changed, 625 insertions, 110 deletions
@@ -10,15 +10,18 @@ build: $(TARGET) $(TARGET): .FORCE $(MAKE) -C kernel + $(MAKE) -C lib $(MAKE) -C usrbin - $(LD) -o $(TARGET) kernel/kernel.o usrbin/usrbin_blob.o + $(LD) -o $(TARGET) kernel/kernel.o usrbin/usrbin_blob.o lib/lib.a clean: $(MAKE) -C kernel clean + $(MAKE) -C lib clean $(MAKE) -C usrbin clean rm -f $(TARGET) run: $(TARGET) qemu-system-x86_64 -s -kernel $(TARGET) + # qemu-system-x86_64 -s -S -kernel $(TARGET) .FORCE: diff --git a/include/asm/io.h b/include/asm/io.h index 6ca5bbc..1c2e5bc 100644 --- a/include/asm/io.h +++ b/include/asm/io.h @@ -6,9 +6,9 @@ #define inb(port) ({ \ unsigned char _val; \ - asm volatile ("inb %%dx, %%al" : "=a" (_val) : "d" (port)); \ + __asm__ volatile ("inb %%dx, %%al" : "=a" (_val) : "d" (port)); \ _val; \ }) #define outb(port, val) \ - asm volatile ("outb %%al, %%dx" : : "d" (port), "a" (val)); + __asm__ volatile ("outb %%al, %%dx" : : "d" (port), "a" (val)); diff --git a/include/asm/system.h b/include/asm/system.h new file mode 100644 index 0000000..02c2f62 --- /dev/null +++ b/include/asm/system.h @@ -0,0 +1,3 @@ +#include <kernel/sched.h> + +volatile void switch_to(struct task_struct*, struct task_state*); diff --git a/include/kernel/memory.h b/include/kernel/memory.h new file mode 100644 index 0000000..7217427 --- /dev/null +++ b/include/kernel/memory.h @@ -0,0 +1,18 @@ +#include <stdint.h> + +#define PGENT 1024 + +typedef uint32_t pte_t; +typedef uint32_t __attribute__((aligned (4096))) ptab_t[PGENT]; +typedef uint32_t pde_t; +typedef uint32_t __attribute__((aligned (4096))) pdir_t[PGENT]; + +extern ptab_t ktab; + +void *alloc_physical_page(void); +int free_physical_page(void*); +void *alloc_physical_pages(unsigned int); + +void *map_page(void*); + +void paging_init(void); diff --git a/include/kernel/sched.h b/include/kernel/sched.h new file mode 100644 index 0000000..fa8e036 --- /dev/null +++ b/include/kernel/sched.h @@ -0,0 +1,26 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include <stdint.h> + +struct task_state { + uint32_t ss; + uint32_t esp; + uint32_t eflags; + uint32_t cs; + uint32_t eip; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp_garbage; + uint32_t ebp; + uint32_t esi; + uint32_t edi; +} __attribute__((packed)); + +struct task_struct { + struct task_state state; +} __attribute__((packed)); + +#endif diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..72c2b2e --- /dev/null +++ b/include/string.h @@ -0,0 +1,37 @@ +#ifndef STRING_H +#define STRING_H + +#include <stdint.h> + +#ifndef NULL +#define NULL ((void*) 0) +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef uint32_t size_t; +#endif + +void* memchr(const void*, int, size_t); +int memcmp(const void*, const void*, size_t); +void* memcpy(void*, const void*, size_t); +void* memmove(void*, const void*, size_t); +void* memset(void*, int, size_t); + +size_t strlen(const char*); +char* strcat(char*, const char*); +char* strncat(char*, const char*, size_t); +char* strchr(const char*, int); +char* strrchr(char*, int); +int strcmp(const char*, const char*); +int strncmp(const char*, const char*, size_t); +char* strcpy(char*, const char*); +char* strncpy(char*, const char*, size_t); +size_t strcspn(const char*, const char*); +size_t strspn(const char*, const char*); +char* strpbrk(const char*, const char*); +char* strstr(const char*, const char*); +char* strtok(char*, const char*); +size_t strxfrm(char*, const char*, size_t); + +#endif diff --git a/kernel/Makefile b/kernel/Makefile index c6cf24e..29b5566 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -4,7 +4,7 @@ SRCS = $(wildcard *.c) ASMS = $(wildcard *.s) OBJS = $(SRCS:.c=.o) $(ASMS:.s=.o) -CFLAGS = -m32 -I../include -ffreestanding -nostdinc -nostdlib -fno-stack-protector -fno-pie -gstabs+ +CFLAGS = -m32 -I../include -ffreestanding -nostdinc -nostdlib -fno-stack-protector -fno-pie -gstabs+ -g LDFLAGS = -m elf_i386 -r ASMFLAGS = -f elf32 diff --git a/kernel/asm.s b/kernel/asm.s new file mode 100644 index 0000000..4abe607 --- /dev/null +++ b/kernel/asm.s @@ -0,0 +1,60 @@ +global switch_to +extern ctask +extern tss + +switch_to: + push ebp + mov ebp, esp + mov eax, [ebp+8] + mov [ctask], eax + mov esi, [ebp+12] + mov ecx, 13 +.loop: + lodsd + push eax + dec ecx + jz .end + jmp .loop +.end: + mov ax, 0x23 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + popa + iret + +; uint32_t ss; +; uint32_t esp; +; uint32_t eflags; +; uint32_t cs; +; uint32_t eip; +; uint32_t eax; +; uint32_t ecx; +; uint32_t edx; +; uint32_t ebx; +; uint32_t esp_garbage; +; uint32_t ebp; +; uint32_t esi; +; uint32_t edi; + +; switch_to: + ; push ebp + ; mov ebp, esp + ; cli + ; mov ax, 0x23 + ; mov ds, ax + ; mov es, ax + ; mov fs, ax + ; mov gs, ax + ; mov eax, esp + ; ; save ESP in the TSS + ; mov [tss+4], eax + ; push dword 0x23 + ; push dword 0x00180000 + ; pushf + ; push dword 0x1B + ; push dword 0x00100000 + ; iret + ; pop ebp + ; ret diff --git a/kernel/boot.s b/kernel/boot.s index 80f8be9..9d948cf 100644 --- a/kernel/boot.s +++ b/kernel/boot.s @@ -22,6 +22,8 @@ section .text kboot: cli ; put the stack pointer near the end of conventional memory + ; WARNING: don't change this without changing the corresponding + ; entry in the TSS mov esp, 0x80000 ; setup descriptor tables call flush_gdt @@ -37,7 +39,7 @@ kboot: tss: dd 0 - dd 0 ; kernel stack pointer + dd 0x80000 ; kernel stack pointer dd 0x10 ; kernel stack segment times 60 db 0 dd 0x13 ; ES segment diff --git a/kernel/kmain.c b/kernel/kmain.c index ece7012..558df42 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -1,12 +1,13 @@ #include <kernel/con.h> +#include <kernel/memory.h> #include <kernel/sys.h> #include <stdint.h> #include <sys/types.h> -uint32_t ticks = 0; - extern void userspace_init(void); +uint32_t ticks = 0; + void kmain(void) { con_init(); diff --git a/kernel/memory.c b/kernel/memory.c new file mode 100644 index 0000000..465b44f --- /dev/null +++ b/kernel/memory.c @@ -0,0 +1,129 @@ +#include <kernel/memory.h> +#include <stdint.h> +#include <sys/types.h> + +static char __attribute__((aligned (4096))) mapped_page[4096]; + +static pdir_t kpdir; + +ptab_t ktab; + +static ptab_t flow; +static ptab_t fupp; + +void *alloc_physical_page(void) { + int i; + void *ret; + + for(i = 0; i < PGENT; i++) { + if(flow[i] & 1) { + ret = (void*) (flow[i] & ~1); + flow[i] = 0; + return ret; + } + + if(fupp[i] & 1) { + ret = (void*) (fupp[i] & ~1); + fupp[i] = 0; + return ret; + } + } + + return NULL; +} + +int free_physical_page(void *page) { + int i; + page = (void*) ((uint32_t) page & ~0xFFF); + + for(int i = 0; i < PGENT; i++) { + if(!(flow[i] & 1)) { + flow[i] = (uint32_t) page | 1; + return 0; + } + + if(!(fupp[i] & 1)) { + fupp[i] = (uint32_t) page | 1; + return 0; + } + } + + return -1; +} + +void *alloc_physical_pages(unsigned int n) { + void *p = NULL; + void *last = NULL; + void **page; + + while(n--) { + p = alloc_physical_page(); + if(p == NULL) { + page = &last; + while(*page) { + free_physical_page(*page); + page = *page; + } + return NULL; + } + + map_page(p); + *((void**) mapped_page) = last; + last = p; + } + + return p; +} + +void *map_page(void *page) { + uint32_t p = (uint32_t) mapped_page; + + /* enforce 4KB page alignment */ + page = (void*) ((uint32_t) page & ~0xFFF); + + ktab[(p >> 12) & 0x3FF] = (uint32_t) page | 0x003; + /* + * invalidate any cached entries for + * the mapped page window. + */ + __asm__ ("invlpg %0" :: "m" (mapped_page)); + + return mapped_page; +} + +void paging_init(void) { + int i; + + /* empty the page directory */ + for(i = 0; i < PGENT; i++) + kpdir[i] = 0; + + /* populate the free page tables */ + for(i = 0; i < PGENT; i++) { + /* populate the lower table */ + flow[i] = (i << 12); + /* only pages >1MB can be allocated */ + if(i >= 0x100) + flow[i] |= 0x001; + /* populate the upper table */ + fupp[i] = ((i << 12) + 0x400000) | 0x001; + } + + /* populate the kernel's page table */ + for(i = 0; i < PGENT; i++) { + ktab[i] = 0; + if(i < 256) + ktab[i] = (i << 12) | 0x003; + } + + /* populate the kernel's page directory */ + kpdir[0] = ((pde_t) ktab) | 0x007; + + __asm__ ( + "mov %%eax, %%cr3\n" + "mov %%cr0, %%eax\n" + "or $0x80000000, %%eax\n" + "mov %%eax, %%cr0\n" + :: "a" (&kpdir) + :); +} diff --git a/kernel/page.s b/kernel/page.s deleted file mode 100644 index 4e40822..0000000 --- a/kernel/page.s +++ /dev/null @@ -1,55 +0,0 @@ -global paging_init - -align 4096 -page_dir: - times 4096 db 0 - -align 4096 -page_tables: - ; two page tables - times 4096 db 0 - times 4096 db 0 -.end: - -; here, we initialize paging. since the IDT -; has yet to be populated, we must take extra -; care as we can't afford to trigger a page -; fault. -paging_init: - push ebp - mov ebp, esp - push ebx - ; populate the page directory - mov eax, page_tables - or eax, 0x007 - mov [page_dir], eax - mov eax, (page_tables+4096) - or eax, 0x007 - mov [page_dir+4], eax - ; populate the page tables - mov ebx, page_tables - mov ecx, ((page_tables.end-page_tables)/4) - mov edx, 0 -.loop: - mov eax, edx - or eax, 0x003 - cmp edx, 0x100000 - jb .skip - or eax, 0x004 -.skip: - mov [ebx], eax - dec ecx - jz .end - add ebx, 4 - add edx, 4096 - jmp .loop -.end: - ; load the page directory and enable paging - mov eax, page_dir - mov cr3, eax - mov eax, cr0 - or eax, 0x80000000 - mov cr0, eax - pop ebx - pop ebp - ret diff --git a/kernel/sched.c b/kernel/sched.c new file mode 100644 index 0000000..f0b79fc --- /dev/null +++ b/kernel/sched.c @@ -0,0 +1,131 @@ +#include <asm/system.h> +#include <kernel/con.h> +#include <kernel/memory.h> +#include <kernel/sched.h> +#include <string.h> +#include <sys/types.h> + +#define USRSTART ((void*) 0x40000000) + +#define pages(n) \ + ((n / 4096) + 1) + +#define tables(n) \ + ((n / 1024) + 1) + +#define getpage(name, p) ({\ + void **_next; \ + _next = map_page(p); \ + name = p; \ + p = *_next; \ + }) + +extern char _usrbin_start; +extern char _usrbin_size; + +struct task_struct *ctask; + +static struct task_struct task; + +static inline void empty_table(void *t) { + int i; + + for(i = 0; i < PGENT; i++) + ((uint32_t*) t)[i] = 0; +} + +void userspace_init(void) { + int i, j; + int c; + size_t totpages, npages, ntables; + void *p, *page, *tab, *map; + void *pdir, *stackt, *stackp; + + size_t usrsize = (size_t) &_usrbin_size; + + npages = pages(usrsize); + ntables = tables(pages(usrsize)); + totpages = npages + ntables + 3; + + /* here we allocate pages to setup the process' + * address space. in addition to the pages that + * will hold the binary image, the following + * pages are allocated: + * - page directory (1 page) + * - page tables + * - stack page (1 page) + * - stack table (1 page) + */ + p = alloc_physical_pages(totpages); + printf("Allocating %x pages for userspace process\n", totpages); + if(p == NULL) { + printf("Failed to allocate memory for userspace!\n"); + return; + } + + getpage(pdir, p); + getpage(stackt, p); + getpage(stackp, p); + printf(" Page directory: 0x%08x\n", (uint32_t) pdir); + printf(" Stack table: 0x%08x\n", (uint32_t) stackt); + printf(" Stack page: 0x%08x\n", (uint32_t) stackp); + printf(" Page tables:\n"); + + /* populate the page directory */ + c = npages; + map = map_page(pdir); + empty_table(map); + for(i = 0; i < ntables; i++) { + /* add the table entry to the directory */ + getpage(tab, p); + printf(" 0x%08x\n", (uint32_t) tab); + map = map_page(pdir); + ((uint32_t*) map)[i + (PGENT / 4)] = (uint32_t) tab | 0x007; + + /* populate the page table */ + map = map_page(tab); + for(j = 0; j < PGENT; j++) { + ((uint32_t*) map)[j] = 0; + if(c <= 0) + continue; + + getpage(page, p); + map = map_page(tab); + ((uint32_t*) map)[j] = (uint32_t) page | 0x007; + c--; + } + } + + /* populate the stack table */ + map = map_page(stackt); + empty_table(map); + ((uint32_t*) map)[PGENT - 1] = (uint32_t) stackp | 0x007; + + /* add the stack page table to the directory */ + map = map_page(pdir); + ((uint32_t*) map)[PGENT - 1] = (uint32_t) stackt | 0x007; + /* add the kernel's page table to the directory */ + ((uint32_t*) map)[0] = (uint32_t) ktab | 0x003; + + __asm__ volatile ("mov %%eax, %%cr3" :: "a" (pdir)); + + memcpy(USRSTART, &_usrbin_start, usrsize); + + /* + * here we initialize the task struct. + * currently, we only setup state information + * necessary to begin execution. + */ + memset(&task, 0, sizeof(task)); + task.state.cs = 0x1B; + task.state.ss = 0x23; + task.state.eip = (uint32_t) USRSTART; + task.state.esp = 0xFFFFFFFF; + __asm__ ( + "pushf\n" \ + "pop %%eax" \ + : "=a" (task.state.eflags) \ + ::); + + switch_to(&task, &task.state); +} diff --git a/kernel/usrspace.s b/kernel/usrspace.s deleted file mode 100644 index 1d20f71..0000000 --- a/kernel/usrspace.s +++ /dev/null @@ -1,45 +0,0 @@ -global userspace_init -extern _binary_usrbin_bin_size -extern _binary_usrbin_bin_start -extern tss - -userspace_init: - push ebp - mov ebp, esp - push esi - push edi - mov ecx, _binary_usrbin_bin_size - mov esi, _binary_usrbin_bin_start - mov edi, 0x100000 -.loop: - movsb - dec ecx - jz .end - jmp .loop -.end: - pop edi - pop esi - call usrcall - pop ebp - ret - -usrcall: - push ebp - mov ebp, esp - cli - mov ax, 0x23 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov eax, esp - ; save ESP in the TSS - mov [tss+4], eax - push dword 0x23 - push dword 0x00180000 - pushf - push dword 0x1B - push dword 0x00100000 - iret - pop ebp - ret diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..13c92f2 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,29 @@ +TARGET = lib.a + +SRCS = $(wildcard *.c) +ASMS = $(wildcard *.s) +OBJS = $(SRCS:.c=.o) $(ASMS:.s=.o) + +CFLAGS = -m32 -I../include -ffreestanding -nostdinc -nostdlib -fno-stack-protector -fno-pie -gstabs+ -g +ASMFLAGS = -f elf32 + +AR = ar +CC = gcc $(CFLAGS) +ASM = nasm $(ASMFLAGS) + +all: build + +build: $(TARGET) + +.s.o: + $(ASM) -o $*.o $^ + +.c.o: + $(CC) -c -o $*.o $^ + +$(TARGET): $(OBJS) + $(AR) rc $(TARGET) $(OBJS) + +clean: + rm -f $(OBJS) + rm -f $(TARGET) diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..0e8fbeb --- /dev/null +++ b/lib/string.c @@ -0,0 +1,173 @@ +#include <string.h> + +void* memchr(const void* s, int c, size_t n) { + unsigned char *p = (unsigned char*) s; + while(n--) { + if(*p != (unsigned char) c) { + p++; + } else { + return p; + } + } + return 0; +} + +int memcmp(const void* s1, const void* s2, size_t n) { + const unsigned char* p1 = (const unsigned char*) s1; + const unsigned char* p2 = (const unsigned char*) s2; + while(n--) { + if(*p1 != *p2) { + return *p1 - *p2; + } else { + p1++, p2++; + } + } + return 0; +} + +void* memcpy(void* dest, const void* src, size_t n) { + char *dp = (char*) dest; + const char *sp = (const char*) src; + while(n--) *dp++ = *sp++; + return dest; +} + +void* memmove(void* dest, const void* src, size_t n) { + unsigned char tmp[n]; + memcpy(tmp, src, n); + memcpy(dest, tmp, n); + return dest; +} + +void* memset(void* s, int c, size_t n) { + unsigned char* p = (unsigned char*) s; + while(n--) *p++ = (unsigned char) c; + return s; +} + +size_t strlen(const char* str) { + const char* s; + for(s = str; *s; ++s) {} + return (s - str); +} + +char* strcat(char* dest, const char* src) { + size_t dest_len = strlen(dest); + size_t i; + + for(i = 0; src[i] != '\0'; i++) { + dest[dest_len + i] = src[i]; + } + dest[dest_len + i] = '\0'; + return dest; +} + +char* strncat(char* dest, const char* src, size_t n) { + size_t dest_len = strlen(dest); + size_t i; + + for(i = 0; i < n && src[i] != '\0'; i++) { + dest[dest_len + i] = src[i]; + } + dest[dest_len + i] = '\0'; + return dest; +} + +char* strchr(const char* s, int c) { + while(*s != (char) c) { + if(!*s++) return 0; + } + return (char*) s; +} + +char* strrchr(char* s, int c) { + char* ret = 0; + do { + if(*s == (char) c) ret = s; + } while(*s++); + return ret; +} + +int strcmp(const char* s1, const char* s2) { + while(*s1 && (*s1 == *s2)) s1++, s2++; + return *(const unsigned char*) s1 - *(const unsigned char*) s2; +} + +int strncmp(const char* s1, const char* s2, size_t n) { + while(n--) { + if(*s1++ != *s2++) { + return *(unsigned char*) (s1 - 1) - *(unsigned char*) (s2 - 1); + } + } + return 0; +} + +char* strcpy(char* dest, const char* src) { + char* ret = dest; + while(*dest++ = *src++); + return ret; +} + +char* strncpy(char* dest, const char* src, size_t n) { + char* ret = dest; + do { + if(!n--) return ret; + } while (*dest++ = *src++); + while(n--) *dest++ = 0; + return ret; +} + +size_t strcspn(const char* s1, const char* s2) { + size_t ret = 0; + while(*s1) { + if(strchr(s2, *s1)) { + return ret; + } else { + s1++, ret++; + } + } + return ret; +} + +size_t strspn(const char* s1, const char* s2) { + size_t ret = 0; + while(*s1 && strchr(s2, *s1++)) ret++; + return ret; +} + +char* strpbrk(const char* s1, const char* s2) { + while(*s1) { + if(strchr(s2, *s1++)) return (char*) --s1; + } + return 0; +} + +char* strstr(const char* s1, const char* s2) { + size_t n = strlen(s2); + while(*s1) { + if(!memcmp(s1++, s2, n)) { + return (char*) (s1 - 1); + } + } + return 0; +} + +char* strtok(char* str, const char* delim) { + static char* p = 0; + if(str) { + p = str; + } else if(!p) { + return 0; + } + str = p + strspn(p, delim); + p = str + strcspn(str, delim); + if(p == str) return p = 0; + p = *p ? *p = 0, p + 1 : 0; + return str; +} + +size_t strxfrm(char* dest, const char* src, size_t n) { + size_t n2 = strlen(src); + if(n > n2) strcpy(dest, src); + return n2; +} diff --git a/usrbin/Makefile b/usrbin/Makefile index 16a607f..9a40cbc 100644 --- a/usrbin/Makefile +++ b/usrbin/Makefile @@ -4,7 +4,7 @@ SRCS = $(wildcard *.c) ASMS = $(wildcard *.s) OBJS = $(SRCS:.c=.o) $(ASMS:.s=.o) -CFLAGS = -m32 -I../include -ffreestanding -nostdinc -nostdlib -fno-stack-protector -fno-pie +CFLAGS = -m32 -I../include -ffreestanding -nostdinc -nostdlib -fno-stack-protector -fno-pie -g LDFLAGS = -m elf_i386 -T link.ld ASMFLAGS = -f elf32 @@ -24,7 +24,10 @@ build: $(TARGET) $(TARGET): $(OBJS) $(LD) -o usrbin.bin $(OBJS) - objcopy -I binary -O elf32-i386 -B i386 usrbin.bin $(TARGET) + objcopy -I binary -O elf32-i386 -B i386 usrbin.bin $(TARGET) \ + --redefine-sym _binary_usrbin_bin_start=_usrbin_start \ + --redefine-sym _binary_usrbin_bin_end=_usrbin_end \ + --redefine-sym _binary_usrbin_bin_size=_usrbin_size clean: rm -f usrbin.bin diff --git a/usrbin/link.ld b/usrbin/link.ld index c1a7a42..57edac9 100644 --- a/usrbin/link.ld +++ b/usrbin/link.ld @@ -1,7 +1,7 @@ OUTPUT_FORMAT(binary) SECTIONS { - . = 0x100000; + . = 0x40000000; .text : { *(.entry); .*(.text) } .data : { *(.data) } .bss : { *(.bss) } |
