├── init ├── obj │ └── .content ├── src │ ├── start.asm │ └── init.bas ├── init.ld └── Makefile ├── drivers ├── pci │ ├── .content │ ├── obj │ │ └── .content │ ├── src │ │ ├── start.asm │ │ └── main.bas │ ├── pci.ld │ └── Makefile ├── bochsvga │ ├── obj │ │ └── .content │ ├── src │ │ └── start.asm │ ├── bochsvga.ld │ └── Makefile ├── keyboard │ ├── obj │ │ └── .content │ ├── src │ │ ├── start.asm │ │ ├── keyboard.bi │ │ ├── sc2kc.bas │ │ └── main.bas │ ├── keyboard.ld │ └── Makefile └── vgaconsole │ ├── obj │ └── .content │ ├── src │ ├── start.asm │ └── main.bas │ ├── vgaconsole.ld │ └── Makefile ├── kernel ├── obj │ └── .content ├── asl.txt ├── kernel.ld ├── include │ ├── pit.bi │ ├── idt.bi │ ├── in_out.bi │ ├── syscall.bi │ ├── kmm.bi │ ├── modules.bi │ ├── mem.bi │ ├── elf.bi │ ├── pic.bi │ ├── string_tokenizer.bi │ ├── spinlock.bi │ ├── interrupt.bi │ ├── zstring.bi │ ├── interrupt_handler.bi │ ├── kernel.bi │ ├── io_man.bi │ ├── syscall_defs.bi │ ├── debug.bi │ ├── cpu.bi │ ├── apic.bi │ ├── isf.bi │ ├── atomic.bi │ ├── uid128.bi │ ├── acpi.bi │ ├── panic.bi │ ├── video.bi │ ├── pmm.bi │ ├── address_space.bi │ ├── gdt.bi │ ├── process.bi │ ├── smp.bi │ ├── vfs.bi │ ├── refcount_smartptr.bi │ ├── thread.bi │ ├── vmm.bi │ ├── intrusive_list.bi │ └── elf32.bi ├── Makefile └── src │ ├── pit.bas │ ├── arch │ ├── x64 │ │ └── atomic_arch.bas │ ├── x86 │ │ ├── atomic_arch.bas │ │ ├── start.asm │ │ ├── trampoline.asm.embedd │ │ └── gdt.bas │ └── arm │ │ └── start.S │ ├── in_out.bas │ ├── assert.bas │ ├── mem.bas │ ├── atomic.bas │ ├── uid128.bas │ ├── spinlock.bas │ ├── cpu.bas │ ├── string_tokenizer.bas │ ├── zstring.bas │ ├── pmm_dma24.bas │ ├── process.bas │ ├── pic.bas │ ├── pmm_normal.bas │ ├── debug.bas │ ├── io_man.bas │ ├── stubs.asm │ ├── interrupt.bas │ ├── address_space.bas │ ├── modules.bas │ ├── elf.bas │ ├── lapic.bas │ ├── interrupt_handler.bas │ ├── panic.bas │ ├── vfs.bas │ ├── main.bas │ ├── pmm.bas │ ├── smp.bas │ └── thread.bas ├── libfrost ├── obj │ └── .content ├── src │ ├── 43.bas │ ├── memory.bas │ ├── io_ports.bas │ ├── irq_handling.bas │ ├── process.bas │ ├── ipc.bas │ ├── vfs.bas │ ├── thread.bas │ └── libfrost_internal.bi ├── Makefile └── frost.bi ├── .gitignore ├── doc └── gpl-3.0.odt └── README.md /init/obj/.content: -------------------------------------------------------------------------------- 1 | # init's object files will go here -------------------------------------------------------------------------------- /drivers/pci/.content: -------------------------------------------------------------------------------- 1 | # init's object files will go here -------------------------------------------------------------------------------- /drivers/pci/obj/.content: -------------------------------------------------------------------------------- 1 | # init's object files will go here -------------------------------------------------------------------------------- /kernel/obj/.content: -------------------------------------------------------------------------------- 1 | # the kernels object files will go here -------------------------------------------------------------------------------- /libfrost/obj/.content: -------------------------------------------------------------------------------- 1 | # init's object files will go here -------------------------------------------------------------------------------- /drivers/bochsvga/obj/.content: -------------------------------------------------------------------------------- 1 | # object files will go here 2 | -------------------------------------------------------------------------------- /drivers/keyboard/obj/.content: -------------------------------------------------------------------------------- 1 | # init's object files will go here -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iso 2 | *.krn 3 | *.elf 4 | *.obj 5 | *.o 6 | *.a 7 | -------------------------------------------------------------------------------- /drivers/vgaconsole/obj/.content: -------------------------------------------------------------------------------- 1 | # init's object files will go here -------------------------------------------------------------------------------- /doc/gpl-3.0.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thrimbor/frost/HEAD/doc/gpl-3.0.odt -------------------------------------------------------------------------------- /drivers/bochsvga/src/start.asm: -------------------------------------------------------------------------------- 1 | extern MAIN 2 | global _start 3 | 4 | section .text 5 | _start: 6 | call MAIN 7 | jmp $ 8 | -------------------------------------------------------------------------------- /drivers/keyboard/src/start.asm: -------------------------------------------------------------------------------- 1 | extern MAIN 2 | global _start 3 | 4 | section .text 5 | _start: 6 | call MAIN 7 | jmp $ 8 | -------------------------------------------------------------------------------- /drivers/keyboard/src/keyboard.bi: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | declare function scancode_to_keycode (set as integer, scancode as ushort) as ubyte 4 | -------------------------------------------------------------------------------- /libfrost/src/43.bas: -------------------------------------------------------------------------------- 1 | #include "libfrost_internal.bi" 2 | 3 | sub frost_syscall_43 (str_ptr as byte ptr) 4 | syscall_param1(43, str_ptr) 5 | end sub 6 | -------------------------------------------------------------------------------- /drivers/pci/src/start.asm: -------------------------------------------------------------------------------- 1 | extern fb_ctor__main 2 | global _start 3 | 4 | section .text 5 | _start: 6 | mov esp, stack 7 | call fb_ctor__main 8 | jmp $ 9 | 10 | section .bss 11 | resb 4096 12 | stack: 13 | -------------------------------------------------------------------------------- /drivers/vgaconsole/src/start.asm: -------------------------------------------------------------------------------- 1 | extern fb_ctor__main 2 | global _start 3 | 4 | section .text 5 | _start: 6 | mov esp, stack 7 | call fb_ctor__main 8 | jmp $ 9 | 10 | section .bss 11 | resb 4096 12 | stack: 13 | -------------------------------------------------------------------------------- /init/src/start.asm: -------------------------------------------------------------------------------- 1 | ;extern fb_ctor__init 2 | ;global _start 3 | 4 | ;section .text 5 | ;_start: 6 | ; call fb_ctor__init 7 | ; jmp $ 8 | 9 | extern MAIN 10 | extern THREADFUNC 11 | global _start 12 | 13 | section .text 14 | _start: 15 | call MAIN 16 | jmp $ 17 | 18 | -------------------------------------------------------------------------------- /init/init.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0x40000000; 6 | 7 | .text : { 8 | *(.text) 9 | } 10 | .data ALIGN(4096) : { 11 | *(.data) 12 | } 13 | .rodata ALIGN(4096) : { 14 | *(.rodata) 15 | } 16 | .bss ALIGN(4096) : { 17 | *(.bss) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /drivers/pci/pci.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0x40000000; 6 | 7 | .text : { 8 | *(.text) 9 | } 10 | .data ALIGN(4096) : { 11 | *(.data) 12 | } 13 | .rodata ALIGN(4096) : { 14 | *(.rodata) 15 | } 16 | .bss ALIGN(4096) : { 17 | *(.bss) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /drivers/bochsvga/bochsvga.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0x40000000; 6 | 7 | .text : { 8 | *(.text) 9 | } 10 | .data ALIGN(4096) : { 11 | *(.data) 12 | } 13 | .rodata ALIGN(4096) : { 14 | *(.rodata) 15 | } 16 | .bss ALIGN(4096) : { 17 | *(.bss) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /drivers/keyboard/keyboard.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0x40000000; 6 | 7 | .text : { 8 | *(.text) 9 | } 10 | .data ALIGN(4096) : { 11 | *(.data) 12 | } 13 | .rodata ALIGN(4096) : { 14 | *(.rodata) 15 | } 16 | .bss ALIGN(4096) : { 17 | *(.bss) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /drivers/vgaconsole/vgaconsole.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0x40000000; 6 | 7 | .text : { 8 | *(.text) 9 | } 10 | .data ALIGN(4096) : { 11 | *(.data) 12 | } 13 | .rodata ALIGN(4096) : { 14 | *(.rodata) 15 | } 16 | .bss ALIGN(4096) : { 17 | *(.bss) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libfrost/src/memory.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | function frost_syscall_memory_allocate_physical (bytes as uinteger, addr as any ptr) as any ptr 5 | syscall_param2_ret(SYSCALL_MEMORY_ALLOCATE_PHYSICAL, function, bytes, addr) 6 | end function 7 | -------------------------------------------------------------------------------- /libfrost/src/io_ports.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | sub frost_syscall_port_request (port as uinteger) 5 | syscall_param1(SYSCALL_PORT_REQUEST, port) 6 | end sub 7 | 8 | sub frost_syscall_port_release (port as uinteger) 9 | syscall_param1(SYSCALL_PORT_RELEASE, port) 10 | end sub 11 | -------------------------------------------------------------------------------- /kernel/asl.txt: -------------------------------------------------------------------------------- 1 | virtual address space layout: 2 | 3 | 0x00000000 - 0x000FFFFF - undefined stuff 4 | 0x00100000 - kernel_end_label - kernel code 5 | 0x10000000 - 0x10100000 - kernel heap 6 | 0x3F800000 - 0x3FBFFFFF - page stack (grows downwards) 7 | 0x3FC00000 - 0x3FFFFFFF - page tables of the current process 8 | 9 | 0x40000000 - 0xFFFFFFFF - userspace 10 | -------------------------------------------------------------------------------- /libfrost/src/irq_handling.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | sub frost_syscall_irq_handler_register (irq as uinteger, handler as any ptr) 5 | syscall_param2(SYSCALL_IRQ_HANDLER_REGISTER, irq, handler) 6 | end sub 7 | 8 | sub frost_syscall_irq_handler_exit (irq as uinteger) 9 | syscall_param1(SYSCALL_IRQ_HANDLER_EXIT, irq) 10 | end sub 11 | -------------------------------------------------------------------------------- /libfrost/src/process.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | function frost_syscall_process_get_pid () as uinteger 5 | syscall_param0_ret(SYSCALL_PROCESS_GET_PID, function) 6 | end function 7 | 8 | function frost_syscall_get_parent_pid () as uinteger 9 | syscall_param0_ret(SYSCALL_PROCESS_GET_PARENT_PID, function) 10 | end function 11 | 12 | 13 | -------------------------------------------------------------------------------- /libfrost/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 3 | 4 | COMPILER = fbc 5 | AR = ar 6 | 7 | CFLAGS = -c -nodeflibs -lang fb -arch 486 8 | ARFLAGS = -cvq 9 | 10 | libfrost.a: $(OBJS) 11 | $(AR) $(ARFLAGS) $@ $^ 12 | 13 | obj/%.o: src/%.bas 14 | $(COMPILER) $(CFLAGS) $^ -o $@ 15 | 16 | clean: 17 | rm -f $(OBJS) libfrost.a 18 | 19 | .PHONY: clean 20 | -------------------------------------------------------------------------------- /libfrost/src/ipc.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | sub frost_syscall_ipc_handler_call (pid as uinteger) 5 | syscall_param1(SYSCALL_IPC_HANDLER_CALL, pid) 6 | end sub 7 | 8 | sub frost_syscall_ipc_handler_set (handler as any ptr) 9 | syscall_param1(SYSCALL_IPC_HANDLER_SET, handler) 10 | end sub 11 | 12 | sub frost_syscall_ipc_handler_exit () 13 | syscall_param0(SYSCALL_IPC_HANDLER_EXIT) 14 | end sub 15 | -------------------------------------------------------------------------------- /libfrost/src/vfs.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | sub frost_syscall_vfs_create_node (nodeinfo as vfs_create_info ptr) 5 | syscall_param1(SYSCALL_VFS_CREATE_NODE, nodeinfo) 6 | end sub 7 | 8 | 'function frost_syscall_vfs_open (path as zstring ptr, flags as uinteger) as uinteger 9 | ' syscall_param2_ret(SYSCALL_VFS_OPEN, function, path, flags) 10 | 'end function 11 | 12 | sub frost_syscall_vfs_open (openinfo as vfs_open_info ptr) 13 | syscall_param1(SYSCALL_VFS_OPEN, openinfo) 14 | end sub 15 | -------------------------------------------------------------------------------- /init/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | SRCS += $(shell find src -name *.asm) 3 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 4 | 5 | COMPILER = fbc 6 | ASSEMBLER = nasm 7 | LINKER = ld 8 | 9 | CFLAGS = -c -nodeflibs -lang fb -arch 486 10 | AFLAGS = -f elf32 11 | LFLAGS = -melf_i386 -Tinit.ld 12 | 13 | init.elf: $(OBJS) 14 | $(LINKER) $(LFLAGS) -o $@ $^ ../libfrost/libfrost.a 15 | 16 | obj/%.o: src/%.bas 17 | $(COMPILER) $(CFLAGS) $^ -o $@ 18 | 19 | obj/%.o: src/%.asm 20 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 21 | 22 | clean: 23 | rm -f $(OBJS) init.elf 24 | 25 | .PHONY: clean 26 | -------------------------------------------------------------------------------- /drivers/pci/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | SRCS += $(shell find src -name *.asm) 3 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 4 | 5 | COMPILER = fbc 6 | ASSEMBLER = nasm 7 | LINKER = ld 8 | 9 | CFLAGS = -c -nodeflibs -lang fb -arch 486 10 | AFLAGS = -f elf32 11 | LFLAGS = -melf_i386 -Tpci.ld 12 | 13 | pci.elf: $(OBJS) 14 | $(LINKER) $(LFLAGS) -o $@ $^ ../../libfrost/libfrost.a 15 | 16 | obj/%.o: src/%.bas 17 | $(COMPILER) $(CFLAGS) $^ -o $@ 18 | 19 | obj/%.o: src/%.asm 20 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 21 | 22 | clean: 23 | rm -f $(OBJS) pci.elf 24 | 25 | .PHONY: clean 26 | -------------------------------------------------------------------------------- /drivers/vgaconsole/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | SRCS += $(shell find src -name *.asm) 3 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 4 | 5 | COMPILER = fbc 6 | ASSEMBLER = nasm 7 | LINKER = ld 8 | 9 | CFLAGS = -c -nodeflibs -lang fb -arch 486 10 | AFLAGS = -f elf32 11 | LFLAGS = -melf_i386 -Tvgaconsole.ld 12 | 13 | vgaconsole.elf: $(OBJS) 14 | $(LINKER) $(LFLAGS) -o $@ $^ 15 | 16 | obj/%.o: src/%.bas 17 | $(COMPILER) $(CFLAGS) $^ -o $@ 18 | 19 | obj/%.o: src/%.asm 20 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 21 | 22 | clean: 23 | rm -f $(OBJS) vgaconsole.elf 24 | 25 | .PHONY: clean 26 | -------------------------------------------------------------------------------- /drivers/bochsvga/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | SRCS += $(shell find src -name *.asm) 3 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 4 | 5 | COMPILER = fbc 6 | ASSEMBLER = nasm 7 | LINKER = ld 8 | 9 | CFLAGS = -c -nodeflibs -lang fb -arch 486 10 | AFLAGS = -f elf32 11 | LFLAGS = -melf_i386 -Tbochsvga.ld 12 | 13 | bochsvga.elf: $(OBJS) 14 | $(LINKER) $(LFLAGS) -o $@ $^ ../../libfrost/libfrost.a 15 | 16 | obj/%.o: src/%.bas 17 | $(COMPILER) $(CFLAGS) $^ -o $@ 18 | 19 | obj/%.o: src/%.asm 20 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 21 | 22 | clean: 23 | rm -f $(OBJS) bochsvga.elf 24 | 25 | .PHONY: clean 26 | -------------------------------------------------------------------------------- /drivers/keyboard/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | SRCS += $(shell find src -name *.asm) 3 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 4 | 5 | COMPILER = fbc 6 | ASSEMBLER = nasm 7 | LINKER = ld 8 | 9 | CFLAGS = -c -nodeflibs -lang fb -arch 486 10 | AFLAGS = -f elf32 11 | LFLAGS = -melf_i386 -Tkeyboard.ld 12 | 13 | keyboard.elf: $(OBJS) 14 | $(LINKER) $(LFLAGS) -o $@ $^ ../../libfrost/libfrost.a 15 | 16 | obj/%.o: src/%.bas 17 | $(COMPILER) $(CFLAGS) $^ -o $@ 18 | 19 | obj/%.o: src/%.asm 20 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 21 | 22 | clean: 23 | rm -f $(OBJS) keyboard.elf 24 | 25 | .PHONY: clean 26 | -------------------------------------------------------------------------------- /libfrost/src/thread.bas: -------------------------------------------------------------------------------- 1 | #include "../../kernel/include/syscall_defs.bi" 2 | #include "libfrost_internal.bi" 3 | 4 | function frost_syscall_thread_get_tid () as uinteger 5 | syscall_param0_ret(SYSCALL_THREAD_GET_TID, function) 6 | end function 7 | 8 | function frost_syscall_thread_create (entry as any ptr, stackaddr as any ptr) as integer 9 | syscall_param2_ret(SYSCALL_THREAD_CREATE, function, entry, stackaddr) 10 | end function 11 | 12 | sub frost_syscall_thread_sleep (ms as uinteger) 13 | syscall_param1(SYSCALL_THREAD_SLEEP, ms) 14 | end sub 15 | 16 | sub frost_syscall_thread_yield () 17 | syscall_param0(SYSCALL_THREAD_YIELD) 18 | end sub 19 | 20 | sub frost_syscall_thread_exit () 21 | syscall_param0(SYSCALL_THREAD_EXIT) 22 | end sub 23 | -------------------------------------------------------------------------------- /kernel/kernel.ld: -------------------------------------------------------------------------------- 1 | /* This is the linkerscript for the frost-kernel */ 2 | ENTRY(_start) 3 | 4 | SECTIONS 5 | { 6 | /* 7 | * This is where we want to have the kernel loaded 8 | * 9 | */ 10 | . = 0x100000; 11 | kernel_start_label = .; 12 | 13 | /* 14 | * The multiboot-header has to be in the first 8 KB, 15 | * so we just put it at the beginning 16 | */ 17 | .text : { 18 | *(multiboot) 19 | *(.text) 20 | } 21 | .data ALIGN(4096) : { 22 | start_ctors = .; 23 | *(.ctor*) 24 | end_ctors = .; 25 | start_dtors = .; 26 | *(.dtor*) 27 | end_dtors = .; 28 | 29 | *(.data) 30 | } 31 | .rodata ALIGN(4096) : { 32 | *(.rodata) 33 | } 34 | .bss ALIGN(4096) : { 35 | *(.bss) 36 | } 37 | 38 | .= ALIGN(4096); 39 | kernel_end_label = .; 40 | } 41 | -------------------------------------------------------------------------------- /kernel/include/pit.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | declare sub pit_set_frequency (frequency as ushort) 22 | -------------------------------------------------------------------------------- /kernel/include/idt.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | declare sub idt_prepare () 22 | declare sub idt_load () 23 | -------------------------------------------------------------------------------- /kernel/include/in_out.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | declare sub outb (port as ushort, value as ubyte) 22 | declare function inb (port as ushort) as ubyte 23 | -------------------------------------------------------------------------------- /kernel/include/syscall.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "syscall_defs.bi" 22 | 23 | declare function syscall_handler (param1 as uinteger, param2 as uinteger, param3 as uinteger, param4 as uinteger) as uinteger 24 | -------------------------------------------------------------------------------- /kernel/include/kmm.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | declare sub kmm_init (start_addr as uinteger, end_addr as uinteger, minimum as uinteger, maximum as uinteger) 22 | declare function kmalloc (size as uinteger) as any ptr 23 | declare sub kfree (addr as any ptr) 24 | -------------------------------------------------------------------------------- /kernel/include/modules.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | #include "multiboot.bi" 21 | #include "process.bi" 22 | 23 | common shared init_process as process_type ptr 24 | 25 | declare sub load_init_module (mbinfo as multiboot_info ptr) 26 | declare sub load_modules (mbinfo as multiboot_info ptr) 27 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(shell find src -name *.bas) 2 | SRCS += $(shell find src -name *.asm) 3 | OBJS = $(addprefix obj/, $(addsuffix .o,$(basename $(notdir $(SRCS))))) 4 | OBJS += obj/trampoline.o 5 | 6 | COMPILER = fbc 7 | ASSEMBLER = nasm 8 | LINKER = ld 9 | 10 | GIT_VERSION := $(shell git describe --dirty --always --tags) 11 | 12 | CFLAGS = -c -nodeflibs -lang fb -arch 486 -i ./include/ -g -d FROST_DEBUG -d FROST_VERSION=\"$(GIT_VERSION)\" 13 | AFLAGS = -f elf32 14 | LFLAGS = -melf_i386 -Tkernel.ld 15 | 16 | frost.krn: $(OBJS) 17 | $(LINKER) $(LFLAGS) -o $@ $^ 18 | 19 | obj/%.o: src/%.bas 20 | $(COMPILER) $(CFLAGS) $^ -o $@ 21 | 22 | obj/%.o: src/arch/x86/%.bas 23 | $(COMPILER) $(CFLAGS) $^ -o $@ 24 | 25 | obj/%.o: src/%.asm 26 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 27 | 28 | obj/%.o: src/arch/x86/%.asm 29 | $(ASSEMBLER) $(AFLAGS) $^ -o $@ 30 | 31 | obj/%.bin: src/arch/x86/%.asm.embedd 32 | $(ASSEMBLER) -f bin $^ -o $@ 33 | 34 | obj/%.o: obj/%.bin 35 | $(LINKER) -melf_i386 -r -b binary $^ -o $@ 36 | 37 | clean: 38 | rm -f $(OBJS) frost.krn 39 | 40 | .PHONY: clean 41 | -------------------------------------------------------------------------------- /kernel/include/mem.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | declare sub memcpy (destination as any ptr, source as any ptr, size as uinteger) 22 | declare sub memset (destination as any ptr, value as ubyte, size as uinteger) 23 | declare function memcmp (s1 as any ptr, s2 as any ptr, size as uinteger) as integer 24 | -------------------------------------------------------------------------------- /kernel/include/elf.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "elf32.bi" 22 | #include "process.bi" 23 | 24 | declare function elf_header_check (header as Elf32_Ehdr ptr) as integer 25 | declare function elf_load_image (process as process_type ptr, thread as thread_type ptr ptr, image as uinteger, size as uinteger) as boolean 26 | -------------------------------------------------------------------------------- /kernel/include/pic.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | #include "kernel.bi" 21 | 22 | declare sub pic_init () 23 | declare sub pic_send_eoi (irq as ubyte) 24 | declare function pic_is_spurious (irq as ubyte) as boolean 25 | declare sub pic_mask (irq as ubyte) 26 | declare sub pic_mask_all () 27 | declare sub pic_unmask (irq as ubyte) 28 | -------------------------------------------------------------------------------- /kernel/include/string_tokenizer.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | type StringTokenizer 22 | public: 23 | declare constructor (s as zstring ptr) 24 | declare function getToken (delimiters as zstring ptr) as zstring ptr 25 | declare destructor () 26 | 27 | private: 28 | original_string as ubyte ptr 29 | string_iterator as ubyte ptr 30 | end type 31 | -------------------------------------------------------------------------------- /kernel/include/spinlock.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include once "kernel.bi" 22 | 23 | type spinlock 24 | public: 25 | declare constructor () 26 | declare sub acquire () 27 | declare function trylock () as boolean 28 | declare sub release () 29 | declare function locked () as boolean 30 | 31 | private: 32 | lockvar as integer 33 | end type 34 | -------------------------------------------------------------------------------- /kernel/src/pit.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "pit.bi" 20 | #include "in_out.bi" 21 | 22 | const COMMAND_PORT as byte = &h43 23 | const DATA_PORT as byte = &h40 24 | 25 | sub pit_set_frequency (frequency as ushort) 26 | frequency = 1193182 \ frequency 27 | outb(COMMAND_PORT, &h34) 28 | outb(DATA_PORT, lobyte(frequency)) 29 | outb(DATA_PORT, hibyte(frequency)) 30 | end sub 31 | -------------------------------------------------------------------------------- /kernel/include/interrupt.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | extern interrupt_legacy_free as boolean 22 | 23 | declare sub interrupt_init () 24 | declare sub interrupt_mask (interrupt as integer) 25 | declare sub interrupt_unmask (interrupt as integer) 26 | declare function interrupt_is_spurious (interrupt as integer) as boolean 27 | declare sub interrupt_eoi (interrupt as integer) 28 | -------------------------------------------------------------------------------- /kernel/include/zstring.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2014 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | declare function zstring_len (zstr as zstring) as uinteger 22 | declare function zstring_instr (zstr as zstring, substr as zstring) as uinteger 23 | declare function zstring_cmp (zstr1 as zstring, zstr2 as zstring) as integer 24 | declare function zstring_ncmp (zstr1 as zstring, zstr2 as zstring, n as uinteger) as integer 25 | -------------------------------------------------------------------------------- /kernel/include/interrupt_handler.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "isf.bi" 22 | #include "process.bi" 23 | #include "kernel.bi" 24 | 25 | declare function register_irq_handler (process as process_type ptr, irq as integer, handler_address as any ptr) as boolean 26 | 27 | '' the global interrupt-handler 28 | declare function handle_interrupt cdecl (isf as interrupt_stack_frame ptr) as interrupt_stack_frame ptr 29 | -------------------------------------------------------------------------------- /kernel/src/arch/x64/atomic_arch.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "atomic.bi" 20 | 21 | function AtomicInt.cmpxchg (oldval as integer, newval as integer) as integer 22 | dim result as integer 23 | 24 | asm 25 | mov rax, [oldval] 26 | mov rbx, [newval] 27 | mov rdx, [this+offsetof(AtomicInt, counter)] 28 | 29 | lock cmpxchg qword ptr [rdx], rbx 30 | mov [result], rax 31 | end asm 32 | 33 | return result 34 | end function 35 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/atomic_arch.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "atomic.bi" 20 | 21 | function AtomicInt.cmpxchg (oldval as integer, newval as integer) as integer 22 | dim result as integer 23 | 24 | asm 25 | mov eax, [oldval] 26 | mov ebx, [newval] 27 | mov edx, [this+offsetof(AtomicInt, counter)] 28 | 29 | lock cmpxchg dword ptr [edx], ebx 30 | mov [result], eax 31 | end asm 32 | 33 | return result 34 | end function 35 | -------------------------------------------------------------------------------- /kernel/src/in_out.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | '' this code is a bit strange, but it's the only comfortable way to use in/out in FreeBASIC without the rtlib (which can't be used in a kernel) 20 | 21 | sub outb (port as ushort, value as ubyte) 22 | asm 23 | movw dx, [port] 24 | movb al, [value] 25 | outb dx, al 26 | end asm 27 | end sub 28 | 29 | function inb (port as ushort) as ubyte 30 | asm 31 | movw dx, [port] 32 | inb al, dx 33 | mov [function], al 34 | end asm 35 | end function 36 | -------------------------------------------------------------------------------- /kernel/include/kernel.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | extern kernel_start_label alias "kernel_start_label" as byte 22 | extern kernel_end_label alias "kernel_end_label" as byte 23 | 24 | #define kernel_start @kernel_start_label 25 | #define kernel_end @kernel_end_label 26 | 27 | #include "gdt.bi" 28 | common shared tss_ptr as task_state_segment ptr 29 | 30 | const nullptr as any ptr = cast(any ptr, 0) 31 | 32 | type paddr_t as uinteger 33 | type vaddr_t as uinteger 34 | type addr_t as uinteger 35 | #define caddr(cf) cuint(cf) 36 | -------------------------------------------------------------------------------- /kernel/include/io_man.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "process.bi" 22 | 23 | declare sub init_ports () 24 | declare function request_port (process as process_type ptr, port as uinteger) as boolean 25 | declare function release_port (process as process_type ptr, port as uinteger) as boolean 26 | declare function request_port_range (process as process_type ptr, start_port as uinteger, length as uinteger) as boolean 27 | declare function release_port_range (process as process_type ptr, start_port as uinteger, length as uinteger) as boolean 28 | -------------------------------------------------------------------------------- /kernel/include/syscall_defs.bi: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum syscalls 4 | SYSCALL_KERNEL_REQUEST_FAST_SYSCALL_INTERFACE 5 | 6 | SYSCALL_PROCESS_GET_PID 7 | SYSCALL_PROCESS_GET_PARENT_PID 8 | SYSCALL_PROCESS_CREATE 9 | SYSCALL_PROCESS_EXIT 10 | SYSCALL_PROCESS_KILL 11 | 12 | SYSCALL_THREAD_GET_TID 13 | SYSCALL_THREAD_CREATE 14 | SYSCALL_THREAD_SLEEP 15 | SYSCALL_THREAD_YIELD 16 | SYSCALL_THREAD_EXIT 17 | 18 | SYSCALL_MEMORY_ALLOCATE_PHYSICAL 19 | 20 | SYSCALL_PORT_REQUEST 21 | SYSCALL_PORT_RELEASE 22 | 23 | SYSCALL_IRQ_HANDLER_REGISTER 24 | SYSCALL_IRQ_HANDLER_EXIT 25 | 26 | SYSCALL_IPC_HANDLER_CALL 27 | SYSCALL_IPC_HANDLER_SET 28 | SYSCALL_IPC_HANDLER_EXIT 29 | 30 | SYSCALL_VFS_CREATE_NODE 31 | SYSCALL_VFS_OPEN 32 | SYSCALL_VFS_CLOSE 33 | SYSCALL_VFS_READ 34 | SYSCALL_VFS_WRITE 35 | 36 | SYSCALL_FORTY_TWO = 42 37 | end enum 38 | 39 | type vfs_create_info 40 | pathname as zstring ptr 41 | nodename as zstring ptr 42 | handler as any ptr 43 | id as integer 44 | end type 45 | 46 | type vfs_open_info 47 | path as zstring ptr '*< the complete path of the node which is to be opened 48 | flags as uinteger 49 | handle as uinteger '*< a caller-defined handle which gets passed to the callback 50 | callback as any ptr '*< the address of a function that gets called as a callback 51 | end type 52 | -------------------------------------------------------------------------------- /kernel/include/debug.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "video.bi" 22 | 23 | const DEBUG_INFO as ubyte = 1 24 | const DEBUG_ERROR as ubyte = 3 25 | 26 | common shared debug_loglevel as ubyte 27 | 28 | declare sub debug_set_loglevel (level as ubyte) 29 | 30 | #macro debug_wlog(level, fstr, args...) 31 | if (level>debug_loglevel) then video_fout(fstr, args) 32 | #endmacro 33 | 34 | #if defined (FROST_DEBUG) 35 | declare sub debug_serial_init () 36 | declare sub debug_serial_putc (char as ubyte) 37 | #endif 38 | 39 | declare sub debug_stacktrace (maxFrames as uinteger) 40 | -------------------------------------------------------------------------------- /kernel/include/cpu.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | #include "kernel.bi" 21 | 22 | declare sub cpu_get_vendor (zstr as zstring ptr) 23 | declare function cpu_has_local_apic () as boolean 24 | declare function cpu_supports_PGE () as boolean 25 | declare function read_msr (msr as uinteger) as ulongint 26 | declare sub write_msr (msr as uinteger, value as ulongint) 27 | declare sub cpu_halt () 28 | declare sub cpu_disable_interrupts () 29 | 30 | const MSR_IA32_SYSENTER_CS as uinteger = &h0174 31 | const MSR_IA32_SYSENTER_ESP as uinteger = &h0175 32 | const MSR_IA32_SYSENTER_EIP as uinteger = &h0176 33 | -------------------------------------------------------------------------------- /kernel/include/apic.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "kernel.bi" 22 | 23 | extern apic_enabled as boolean 24 | 25 | declare sub set_interrupt_override (irq as uinteger, gsi as uinteger, active_high as boolean, edge_triggered as boolean) 26 | declare sub lapic_init () 27 | declare sub lapic_eoi () 28 | declare sub ioapic_init () 29 | declare sub lapic_startup_ipi (trampoline_addr as any ptr) 30 | declare sub ioapic_unmask_irq (irq as uinteger) 31 | declare sub ioapic_mask_irq (irq as uinteger) 32 | declare sub ioapic_register (base_p as uinteger, global_system_interrupt_base as uinteger) 33 | -------------------------------------------------------------------------------- /kernel/include/isf.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | type interrupt_stack_frame field=1 22 | exit_with_iret as uinteger 23 | 24 | '' saved per asm-code: 25 | eax as uinteger 26 | ebx as uinteger 27 | ecx as uinteger 28 | edx as uinteger 29 | esi as uinteger 30 | edi as uinteger 31 | ebp as uinteger 32 | 33 | '' saved by asm-code to identify the interrupt 34 | int_nr as uinteger 35 | errorcode as uinteger 36 | 37 | '' saved automatically by the cpu: 38 | eip as uinteger 39 | cs as uinteger 40 | eflags as uinteger 41 | esp as uinteger 42 | ss as uinteger 43 | end type 44 | -------------------------------------------------------------------------------- /libfrost/src/libfrost_internal.bi: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #macro syscall_param0(syscall_nr) 4 | asm 5 | mov eax, syscall_nr 6 | int &hFF 7 | end asm 8 | #endmacro 9 | 10 | #macro syscall_param1(syscall_nr, a) 11 | asm 12 | mov eax, syscall_nr 13 | mov ebx, [a] 14 | int &hFF 15 | end asm 16 | #endmacro 17 | 18 | #macro syscall_param2(syscall_nr, a, b) 19 | asm 20 | mov eax, syscall_nr 21 | mov ebx, [a] 22 | mov esi, [b] 23 | int &hFF 24 | end asm 25 | #endmacro 26 | 27 | #macro syscall_param3(syscall_nr, a, b, c) 28 | asm 29 | mov eax, syscall_nr 30 | mov ebx, [a] 31 | mov esi, [b] 32 | mov edi, [c] 33 | int &hFF 34 | end asm 35 | #endmacro 36 | 37 | #macro syscall_param0_ret(syscall_nr, ret) 38 | asm 39 | mov eax, syscall_nr 40 | int &hFF 41 | mov [ret], eax 42 | end asm 43 | #endmacro 44 | 45 | #macro syscall_param1_ret(syscall_nr, ret, a) 46 | asm 47 | mov eax, syscall_nr 48 | mov ebx, [a] 49 | int &hFF 50 | mov [ret], eax 51 | end asm 52 | #endmacro 53 | 54 | #macro syscall_param2_ret(syscall_nr, ret, a, b) 55 | asm 56 | mov eax, syscall_nr 57 | mov ebx, [a] 58 | mov esi, [b] 59 | int &hFF 60 | mov [ret], eax 61 | end asm 62 | #endmacro 63 | 64 | #macro syscall_param3_ret(syscall_nr, ret, a, b, c) 65 | asm 66 | mov eax, syscall_nr 67 | mov ebx, [a] 68 | mov esi, [b] 69 | mov edi, [c] 70 | int &hFF 71 | mov [ret], eax 72 | end asm 73 | #endmacro 74 | -------------------------------------------------------------------------------- /kernel/include/atomic.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | 22 | type AtomicInt 23 | public: 24 | declare sub inc () 25 | declare sub dec () 26 | declare function get () as integer 27 | declare function cmpxchg (oldval as integer, newval as integer) as integer 28 | declare function add (value as integer) as integer 29 | declare function subtract (value as integer) as integer 30 | declare function sub_and_test (value as integer) as boolean 31 | 32 | declare constructor () 33 | declare constructor (i as integer) 34 | private: 35 | counter as integer 36 | end type 37 | -------------------------------------------------------------------------------- /libfrost/frost.bi: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../kernel/include/syscall_defs.bi" 4 | 5 | declare function frost_syscall_process_get_pid () as uinteger 6 | declare function frost_syscall_get_parent_pid () as uinteger 7 | 8 | declare function frost_syscall_thread_get_tid () as uinteger 9 | declare function frost_syscall_thread_create (entry as any ptr, stackaddr as any ptr) as integer 10 | declare sub frost_syscall_thread_sleep (ms as uinteger) 11 | declare sub frost_syscall_thread_yield () 12 | declare sub frost_syscall_thread_exit () 13 | 14 | declare function frost_syscall_memory_allocate_physical (bytes as uinteger, addr as any ptr) as any ptr 15 | 16 | declare sub frost_syscall_port_request (port as uinteger) 17 | declare sub frost_syscall_port_release (port as uinteger) 18 | 19 | declare sub frost_syscall_irq_handler_register (irq as uinteger, function_pointer as any ptr) 20 | declare sub frost_syscall_irq_handler_exit (irq as uinteger) 21 | 22 | declare sub frost_syscall_ipc_handler_call (pid as uinteger) 23 | declare sub frost_syscall_ipc_handler_set (handler as any ptr) 24 | declare sub frost_syscall_ipc_handler_exit () 25 | 26 | declare sub frost_syscall_vfs_create_node (nodeinfo as vfs_create_info ptr) 27 | 'declare function frost_syscall_vfs_open (path as zstring ptr, flags as uinteger) as uinteger 28 | declare sub frost_syscall_vfs_open (openinfo as vfs_open_info ptr) 29 | 30 | declare sub frost_syscall_43 (str_ptr as byte ptr) 31 | -------------------------------------------------------------------------------- /kernel/include/uid128.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "spinlock.bi" 22 | 23 | type uid128 24 | #ifdef __FB_BIGENDIAN__ 25 | h as uinteger<64> 26 | l as uinteger<64> 27 | #else 28 | l as uinteger<64> 29 | h as uinteger<64> 30 | #endif 31 | 32 | declare constructor (h as uinteger<64>, l as uinteger<64>) 33 | declare constructor (id as uid128) 34 | declare constructor () 35 | declare sub inc () 36 | end type 37 | 38 | type uid128_generator 39 | current_id as uid128 40 | id_lock as spinlock 41 | 42 | declare constructor () 43 | declare constructor (id as uid128) 44 | declare function generate () as uid128 45 | end type 46 | -------------------------------------------------------------------------------- /kernel/src/assert.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "video.bi" 20 | #include "debug.bi" 21 | #include "cpu.bi" 22 | 23 | #if defined (FROST_DEBUG) 24 | sub _fb_Assert alias "fb_Assert" (byval fname as zstring ptr, byval linenum as integer, byval funcname as zstring ptr, byval expression as zstring ptr) 25 | printk(LOG_ERR !"%s(%i): assertion failed at %s: %s\n", fname, linenum, funcname, expression) 26 | debug_stacktrace(10) 27 | cpu_halt() 28 | end sub 29 | 30 | sub _fb_AssertWarn alias "fb_AssertWarn" (byval fname as zstring ptr, byval linenum as integer, byval funcname as zstring ptr, byval expression as zstring ptr) 31 | printk(LOG_ERR !"%s(%i): assertion failed at %s: %s\n", fname, linenum, funcname, expression) 32 | end sub 33 | #endif 34 | -------------------------------------------------------------------------------- /drivers/vgaconsole/src/main.bas: -------------------------------------------------------------------------------- 1 | #include "../../../kernel/include/syscall_defs.bi" 2 | 3 | declare sub _fb_Out cdecl alias "fb_Out" (port as ushort, value as ubyte) 4 | declare function _fb_In cdecl alias "fb_In" (port as ushort) as ubyte 5 | 6 | asm 7 | .global fb_ctor__main 8 | end asm 9 | 10 | '' request access to the textbuffer 11 | dim buffer as byte ptr 12 | 13 | asm 14 | mov eax, syscalls.SYSCALL_MEMORY_ALLOCATE_PHYSICAL 15 | mov ebx, 4096 16 | mov ecx, &hb8000 17 | int &hFF 18 | mov [buffer], eax 19 | end asm 20 | 21 | asm 22 | mov eax, syscalls.SYSCALL_PORT_REQUEST 23 | mov ebx, &h3D4 24 | int &hFF 25 | mov eax, syscalls.SYSCALL_PORT_REQUEST 26 | mov ebx, &h3D5 27 | int &hFF 28 | end asm 29 | 30 | out(&h3D4, 14) 31 | out(&h3D5, &h07) 32 | out(&h3D4, 15) 33 | out(&h3D5, &hD0) 34 | 35 | 'for x as uinteger = 0 to 4000 36 | ' buffer[x] = 0 37 | 'next 38 | 39 | dim r as uinteger = 0 40 | 41 | dim x as byte ptr = strptr("this is a test from the vgaconsole-driver!") 42 | dim c as uinteger = 0 43 | while (x[c] <> 0) 44 | buffer[r] = x[c] 45 | c += 1 46 | r += 1 47 | buffer[r] = 7 48 | r += 1 49 | wend 50 | 51 | 52 | asm jmp $ 53 | 54 | 55 | sub _fb_Out cdecl alias "fb_Out" (port as ushort, value as ubyte) 56 | asm 57 | movw dx, [port] 58 | movb al, [value] 59 | outb dx, al 60 | end asm 61 | end sub 62 | 63 | function _fb_In cdecl alias "fb_In" (port as ushort) as ubyte 64 | asm 65 | movw dx, [port] 66 | inb al, dx 67 | mov [function], al 68 | end asm 69 | end function 70 | -------------------------------------------------------------------------------- /kernel/include/acpi.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | type rsdp_descriptor field=1 22 | signature as zstring*8 23 | checksum as ubyte 24 | oemid as zstring*6 25 | revision as ubyte 26 | rsdt_address as uinteger<32> 27 | end type 28 | 29 | type rsdp_descriptor_20 field=1 30 | firstPart as rsdp_descriptor 31 | 32 | length as uinteger<32> 33 | xsdt_address as uinteger<64> 34 | extended_checksum as ubyte 35 | reserved as zstring*3 36 | end type 37 | 38 | type sdt_header field=1 39 | signature as zstring*4 40 | length as uinteger<32> 41 | revision as ubyte 42 | checksum as ubyte 43 | oemid as zstring*6 44 | oemtableid as zstring*8 45 | oemrevision as uinteger<32> 46 | creatorid as uinteger<32> 47 | creatorrevision as uinteger<32> 48 | end type 49 | 50 | declare sub acpi_init () 51 | -------------------------------------------------------------------------------- /kernel/include/panic.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "kernel.bi" 22 | #include "isf.bi" 23 | #include "video.bi" 24 | #include "cpu.bi" 25 | 26 | common shared panic_clear_on_panic as boolean 27 | declare sub panic_set_clear_on_panic (b as boolean) 28 | declare sub panic_exception (isf as interrupt_stack_frame ptr) 29 | declare sub panic_hlt () 30 | 31 | #macro panic_error (msg, params...) 32 | cpu_disable_interrupts() 33 | if (panic_clear_on_panic) then video_clean() 34 | printk(LOG_ERR COLOR_RED !"\n--------------------------------------------------------------------------------") 35 | printk(LOG_ERR !"\nKERNEL PANIC\n") 36 | printk(LOG_ERR !"file: %s, function: %s, line: %u\n\n", @__FILE__, @__FUNCTION__, cuint(__LINE__)) 37 | printk(LOG_ERR !"reason: ") 38 | printk(LOG_ERR msg, params) 39 | 40 | panic_hlt() 41 | #endmacro 42 | -------------------------------------------------------------------------------- /kernel/include/video.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #define LOG_DEBUG !"\0022" 22 | #define LOG_INFO !"\0021" 23 | #define LOG_ERR !"\0020" 24 | 25 | #define LOGLEVEL_DEBUG 2 26 | #define LOGLEVEL_INFO 1 27 | #define LOGLEVEL_ERR 0 28 | 29 | #define COLOR_BLACK !"\27[30m" 30 | #define COLOR_RED !"\27[31m" 31 | #define COLOR_GREEN !"\27[32m" 32 | #define COLOR_YELLOW !"\27[33m" 33 | #define COLOR_BLUE !"\27[34m" 34 | #define COLOR_MAGENTA !"\27[35m" 35 | #define COLOR_CYAN !"\27[36m" 36 | #define COLOR_WHITE !"\27[37m" 37 | #define COLOR_RESET !"\27[0m" 38 | 39 | declare sub video_serial_set_colorized (b as integer) 40 | declare sub printk (format_string as const zstring, ...) 41 | declare sub video_clean () 42 | declare sub video_hide_cursor () 43 | declare sub video_show_cursor () 44 | declare sub video_move_cursor (x as ubyte, y as ubyte) 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FROST 2 | ====== 3 | 4 | #### What is FROST? #### 5 | FROST is a 32-bit operating system based on a microkernel. It is written 6 | entirely in FreeBASIC and Assembly. 7 | 8 | #### Dependencies #### 9 | - fbc, tested with 1.05.0 (the FreeBASIC compiler, available on freebasic.net) 10 | - nasm, tested with 2.11.08 (the Netwide Assembler, available on nasm.us) 11 | - GNU make, GNU assembler and the GNU linker 12 | 13 | #### Building FROST #### 14 | To build the kernel, you can type "make" in the "kernel" directory. You will then 15 | get a file called "frost.krn" which is the kernel. 16 | Building the init-process is very similar. 17 | If you want to get a full iso with grub2 and a menu, type "./build_iso.sh" in 18 | the "build"-directory. You will then get a file called "frost.iso" which is 19 | the iso-image. 20 | On some Linux distributions the script will fail because they contain 21 | genisoimage from cdrkit instead of mkisofs from cdrtools. You can create 22 | a link on genisoimage named mkisofs, but I strongly recommend installing 23 | cdrtools instead of cdrkit. If cdrtools is not available on your distribution, 24 | please contact its maintainers (I don't want to get into a debate here, but 25 | cdrkit received it's last commit three years ago). 26 | 27 | #### Directory layout #### 28 | 29 | - ./kernel/src/ The source of the kernel 30 | - ./kernel/include/ The headers of the kernel 31 | - ./build/ Contains the build-scripts and the grub.cfg 32 | - ./doc/ Contains documentation for FROST 33 | - ./init/ Contains the source of the init-process 34 | -------------------------------------------------------------------------------- /kernel/include/pmm.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "kernel.bi" 22 | #include "multiboot.bi" 23 | 24 | const PAGE_SIZE = 4096 25 | const PMM_STACK_TOP = &h3FC00000 26 | const PMM_STACK_ENTRIES_PER_PAGE = 1024 27 | 28 | const PMM_ZONE_DMA24 as uinteger = 1 29 | const PMM_ZONE_NORMAL as uinteger = 2 30 | 31 | declare sub pmm_init (mbinfo as multiboot_info ptr, zone as uinteger) 32 | declare function pmm_alloc (zone as uinteger = PMM_ZONE_NORMAL) as any ptr 33 | declare sub pmm_free (page as any ptr) 34 | declare function pmm_get_total () as uinteger 35 | declare function pmm_get_free () as uinteger 36 | 37 | declare sub pmm_init_dma24 () 38 | declare function pmm_alloc_dma24 () as any ptr 39 | declare sub pmm_free_dma24 (page as any ptr) 40 | declare function pmm_alloc_normal () as any ptr 41 | declare sub pmm_free_normal (addr as any ptr) 42 | -------------------------------------------------------------------------------- /kernel/src/mem.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "mem.bi" 20 | 21 | sub memcpy (destination as any ptr, source as any ptr, size as uinteger) 22 | asm 23 | mov ecx, [size] 24 | mov edi, [destination] 25 | mov esi, [source] 26 | 27 | rep movsb 28 | end asm 29 | end sub 30 | 31 | sub memset (destination as any ptr, value as ubyte, size as uinteger) 32 | asm 33 | mov ecx, [size] 34 | mov edi, [destination] 35 | mov al, [value] 36 | 37 | rep stosb 38 | end asm 39 | end sub 40 | 41 | function memcmp (s1 as any ptr, s2 as any ptr, size as uinteger) as integer 42 | dim p1 as ubyte ptr = s1 43 | dim p2 as ubyte ptr = s2 44 | 45 | while (size > 0) 46 | if (*p1 <> *p2) then 47 | return *p1 - *p2 48 | end if 49 | 50 | p1 += 1 51 | p2 += 1 52 | size -= 1 53 | wend 54 | 55 | return 0 56 | end function 57 | -------------------------------------------------------------------------------- /kernel/include/address_space.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "kernel.bi" 22 | #include "intrusive_list.bi" 23 | 24 | DECLARE_LIST(address_space_area) 25 | 26 | type address_space_area 27 | address as any ptr 28 | pages as uinteger 29 | flags as uinteger 30 | description as zstring ptr 31 | 32 | list as Listtype(address_space_area) = Listtype(address_space_area)(offsetof(address_space_area, list)) 33 | 34 | declare constructor (address as any ptr, pages as uinteger, flags as uinteger = 0, description as zstring ptr = nullptr) 35 | declare operator new (size as uinteger) as any ptr 36 | declare operator delete (buffer as any ptr) 37 | end type 38 | 39 | type address_space 40 | areas as Listtype(address_space_area) 41 | 42 | declare function allocate_area (pages as uinteger, flags as uinteger = 0, description as zstring ptr = nullptr) as address_space_area ptr 43 | declare sub insert_area (area as address_space_area ptr) 44 | end type 45 | -------------------------------------------------------------------------------- /kernel/src/atomic.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "atomic.bi" 20 | 21 | sub AtomicInt.inc () 22 | this.add(1) 23 | end sub 24 | 25 | sub AtomicInt.dec () 26 | this.add(-1) 27 | end sub 28 | 29 | function AtomicInt.get () as integer 30 | return this.counter 31 | end function 32 | 33 | function AtomicInt.add (value as integer) as integer 34 | dim c as integer = this.counter 35 | dim old as integer 36 | 37 | do 38 | old = this.cmpxchg(c, c+value) 39 | if (old = c) then exit do 40 | c = old 41 | loop 42 | 43 | return c+value 44 | end function 45 | 46 | function AtomicInt.subtract (value as integer) as integer 47 | return this.add(-value) 48 | end function 49 | 50 | function AtomicInt.sub_and_test (value as integer) as boolean 51 | return this.subtract(value) = 0 52 | end function 53 | 54 | constructor AtomicInt () 55 | this.counter = 0 56 | end constructor 57 | 58 | constructor AtomicInt (i as integer) 59 | this.counter = i 60 | end constructor 61 | -------------------------------------------------------------------------------- /kernel/src/uid128.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "uid128.bi" 20 | 21 | constructor uid128 (h as uinteger<64>, l as uinteger<64>) 22 | this.h = h 23 | this.l = l 24 | end constructor 25 | 26 | constructor uid128 (id as uid128) 27 | this.h = id.h 28 | this.l = id.l 29 | end constructor 30 | 31 | constructor uid128 () 32 | this.l = 0 33 | this.h = 0 34 | end constructor 35 | 36 | sub uid128.inc () 37 | dim r as uid128 38 | r.l = this.l+1 39 | r.h = this.h + iif(r.l < this.l, 1, 0) 40 | 41 | this.l = r.l 42 | this.h = r.h 43 | end sub 44 | 45 | constructor uid128_generator () 46 | 47 | end constructor 48 | 49 | constructor uid128_generator (id as uid128) 50 | this.id_lock.acquire() 51 | this.current_id = id 52 | this.id_lock.release() 53 | end constructor 54 | 55 | function uid128_generator.generate () as uid128 56 | this.id_lock.acquire() 57 | function = this.current_id 58 | this.current_id.inc() 59 | this.id_lock.release() 60 | end function 61 | -------------------------------------------------------------------------------- /kernel/include/gdt.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | type task_state_segment field=1 22 | backlink as uinteger 23 | esp0 as uinteger 24 | ss0 as uinteger 25 | esp1 as uinteger 26 | ss1 as uinteger 27 | esp2 as uinteger 28 | ss2 as uinteger 29 | cr3 as uinteger 30 | eip as uinteger 31 | eflags as uinteger 32 | eax as uinteger 33 | ecx as uinteger 34 | edx as uinteger 35 | ebx as uinteger 36 | esp as uinteger 37 | ebp as uinteger 38 | esi as uinteger 39 | edi as uinteger 40 | es as uinteger 41 | cs as uinteger 42 | ss as uinteger 43 | ds as uinteger 44 | fs as uinteger 45 | gs as uinteger 46 | ldt as uinteger 47 | trace_trap as ushort 48 | io_bitmap_offset as ushort 49 | io_bitmap(0 to 2047) as uinteger 50 | io_bitmap_end as ubyte 51 | end type 52 | 53 | const TSS_IO_BITMAP_OFFSET as ushort = cushort(cuint(@(cast(task_state_segment ptr, 0)->io_bitmap(0)))) 54 | const TSS_IO_BITMAP_NOT_LOADED as ushort = sizeof(task_state_segment)+&h100 55 | 56 | declare sub gdt_prepare () 57 | declare sub gdt_load () 58 | -------------------------------------------------------------------------------- /kernel/src/spinlock.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "spinlock.bi" 20 | #include "kernel.bi" 21 | 22 | constructor spinlock () 23 | this.lockvar = 0 24 | end constructor 25 | 26 | sub spinlock.acquire () 27 | dim slock as integer ptr = @this.lockvar 28 | asm 29 | mov ecx, [slock] 30 | .acquire: 31 | lock bts dword ptr [ecx], 0 32 | jnc .acquired 33 | .retest: 34 | pause 35 | test dword ptr [ecx], 1 36 | je .retest 37 | 38 | lock bts dword ptr [ecx], 0 39 | jc .retest 40 | .acquired: 41 | end asm 42 | end sub 43 | 44 | function spinlock.trylock () as boolean 45 | dim slock as integer ptr = @this.lockvar 46 | asm 47 | mov ecx, [slock] 48 | lock bts dword ptr [ecx], 0 49 | jc .not_locked 50 | mov dword ptr [function], true 51 | jmp .fend 52 | .not_locked: 53 | mov dword ptr [function], false 54 | .fend: 55 | end asm 56 | end function 57 | 58 | sub spinlock.release () 59 | this.lockvar = 0 60 | end sub 61 | 62 | function spinlock.locked () as boolean 63 | return (this.lockvar <> 0) 64 | end function 65 | -------------------------------------------------------------------------------- /init/src/init.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "../libfrost/frost.bi" 20 | 'asm 21 | ' .global fb_ctor__init 22 | 'end asm 23 | 24 | sub vfs_handler (node_id as uinteger) 25 | frost_syscall_43(strptr("vfs handler called")) 26 | '' FIXME 27 | frost_syscall_thread_exit() 28 | 'do : loop 29 | end sub 30 | 31 | sub open_callback () 32 | frost_syscall_43(strptr("open-callback called")) 33 | '' FIXME 34 | frost_syscall_thread_exit() 35 | 'do : loop 36 | end sub 37 | 38 | sub main () 39 | frost_syscall_43(strptr("this is a test")) 40 | 41 | dim ninfo as vfs_create_info 42 | ninfo.pathname = strptr("/vfs_2/testnode") 43 | ninfo.nodename = strptr("INIT_WAS_HERE") 44 | ninfo.handler = @vfs_handler 45 | ninfo.id = 0 46 | frost_syscall_vfs_create_node(@ninfo) 47 | 48 | dim openinfo as vfs_open_info 49 | openinfo.path = strptr("/vfs_2/testnode/INIT_WAS_HERE") 50 | openinfo.flags = &hDEADC0DE 51 | openinfo.handle = &hDEADBEEF 52 | openinfo.callback = @open_callback 53 | frost_syscall_vfs_open(@openinfo) 54 | 55 | do 56 | frost_syscall_thread_yield() 57 | loop 58 | end sub 59 | -------------------------------------------------------------------------------- /kernel/include/process.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "isf.bi" 22 | #include "vmm.bi" 23 | #include "elf32.bi" 24 | #include "multiboot.bi" 25 | #include "thread.bi" 26 | #include "spinlock.bi" 27 | #include "address_space.bi" 28 | #include "vfs.bi" 29 | 30 | DECLARE_LIST(process_type) 31 | 32 | type process_type 33 | id as uinteger 34 | 35 | parent as process_type ptr 36 | 37 | context as vmm_context 38 | 39 | a_s as address_space 40 | 41 | state as ubyte 42 | 43 | ipc_handler as any ptr 44 | 45 | io_bitmap as uinteger ptr 46 | 47 | thread_list as Listtype(thread_type) 48 | next_tid as uinteger 49 | tid_lock as spinlock 50 | 51 | process_list as Listtype(process_type) = Listtype(process_type)(offsetof(process_type, process_list)) 52 | 53 | file_descriptors as Listtype(vfs_fd) 54 | 55 | declare operator new (size as uinteger) as any ptr 56 | declare operator new[] (size as uinteger) as any ptr 57 | declare operator delete (buffer as any ptr) 58 | 59 | declare constructor (parent as process_type ptr = 0) 60 | declare function get_tid () as uinteger 61 | end type 62 | 63 | declare sub process_remove_thread (thread as thread_type ptr) 64 | declare sub process_destroy (process as process_type ptr) 65 | -------------------------------------------------------------------------------- /kernel/src/arch/arm/start.S: -------------------------------------------------------------------------------- 1 | // FROST x86 microkernel 2 | // Copyright (C) 2010-2016 Stefan Schmidt 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | .extern MAIN 18 | .extern KINIT 19 | 20 | .globl _start 21 | 22 | // First we define some constants here, 23 | // then the multiboot header follows. 24 | // Notice that the mb-header has it's own section 25 | // which is mapped to the beginning of .text by 26 | // the linkerscript to prevent it from falling behind 27 | // the first 8KB of the kernel (which would mean problems with grub). 28 | 29 | .section multiboot 30 | .align 4 31 | 32 | .set MULTIBOOT_HEADER_MAGIC, 0x1BADB002 33 | .set MULTIBOOT_PAGE_ALIGN, 0x00000001 34 | .set MULTIBOOT_MEMORY_INFO, 0x00000002 35 | .set MB_FLAGS, MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO 36 | .set MB_CHECKSUM, -(MULTIBOOT_HEADER_MAGIC+MB_FLAGS) 37 | 38 | .long MULTIBOOT_HEADER_MAGIC 39 | .long MB_FLAGS 40 | .long MB_CHECKSUM 41 | 42 | // This is the entry-point of the kernel. 43 | .section .text 44 | _start: 45 | ldr sp, =kernelstack // set up the stack 46 | blx KINIT 47 | blx MAIN // multiboot pointer and magic number are passed in registers 48 | 49 | _halt: 50 | wfe 51 | b _halt 52 | 53 | // 4KB stack for the kernel should be enough ;) 54 | // The label comes after the 4KB because the stack grows downwards. 55 | .section .bss 56 | .space 4096 57 | kernelstack: 58 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/start.asm: -------------------------------------------------------------------------------- 1 | ; FROST x86 microkernel 2 | ; Copyright (C) 2010-2014 Stefan Schmidt 3 | ; 4 | ; This program is free software: you can redistribute it and/or modify 5 | ; it under the terms of the GNU General Public License as published by 6 | ; the Free Software Foundation, either version 3 of the License, or 7 | ; (at your option) any later version. 8 | ; 9 | ; This program is distributed in the hope that it will be useful, 10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ; GNU General Public License for more details. 13 | ; 14 | ; You should have received a copy of the GNU General Public License 15 | ; along with this program. If not, see . 16 | extern MAIN 17 | extern KINIT 18 | global _start 19 | 20 | 21 | ; First we define some constants here, 22 | ; then the multiboot header follows. 23 | ; Notice that the mb-header has it's own section 24 | ; which is mapped to the beginning of .text by 25 | ; the linkerscript to prevent it from falling behind 26 | ; the first 8KB of the kernel (which would mean problems with grub). 27 | section multiboot 28 | align 4 29 | 30 | MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 31 | MULTIBOOT_PAGE_ALIGN equ 0x00000001 32 | MULTIBOOT_MEMORY_INFO equ 0x00000002 33 | MB_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO 34 | MB_CHECKSUM equ -MULTIBOOT_HEADER_MAGIC-MB_FLAGS 35 | 36 | dd MULTIBOOT_HEADER_MAGIC 37 | dd MB_FLAGS 38 | dd MB_CHECKSUM 39 | 40 | 41 | ; This is the entry-point of the kernel. 42 | section .text 43 | _start: 44 | cli ;; no interrupts during initialization 45 | mov esp, kernelstack ;; set up the stack 46 | push ebx ;; pointer to the multiboot structure 47 | push eax ;; push the multiboot magic number 48 | call KINIT 49 | call MAIN 50 | 51 | cli 52 | hlt 53 | 54 | ; 4KB stack for the kernel should be enough ;) 55 | ; The label comes after the 4KB because the stack grows downwards. 56 | section .bss 57 | resb 4096 58 | kernelstack: 59 | -------------------------------------------------------------------------------- /drivers/keyboard/src/sc2kc.bas: -------------------------------------------------------------------------------- 1 | dim shared scancode_table (0 to 127) as ubyte = { _ 2 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, _ 3 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, _ 4 | 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, _ 5 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, _ 6 | 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, _ 7 | 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, _ 8 | 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, _ 9 | 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, _ 10 | 80, 81, 82, 84, 00, 00, 86, 87, 88, 00, _ 11 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 12 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 13 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 14 | 00, 00, 00, 00, 00, 00, 00, 00 } 15 | 16 | dim shared e0code_table (0 to 127) as ubyte = { _ 17 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 18 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 19 | 00, 00, 00, 00, 00, 00, 00, 00, 96, 97, _ 20 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 21 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 22 | 00, 00, 00, 99, 00, 00, 100, 00, 00, 00, _ 23 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 24 | 00, 102, 103, 104, 00, 105, 00, 106, 00, 107, _ 25 | 108, 109, 110, 111, 00, 00, 00, 00, 00, 00, _ 26 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 27 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 28 | 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, _ 29 | 00, 00, 00, 00, 00, 00, 00, 00 } 30 | 31 | function scancode_to_keycode (set as integer, scancode as ushort) as ubyte 32 | dim keycode as ubyte = 0 33 | 34 | select case (set) 35 | case 0: 36 | '' normal scancode 37 | keycode = scancode_table(scancode) 38 | case 1: 39 | '' e0-code 40 | keycode = e0code_table(scancode) 41 | case 2: 42 | '' e1-code 43 | select case (scancode) 44 | case &h451D: 45 | keycode = 119 46 | case else: 47 | keycode = 0 48 | end select 49 | case else 50 | keycode = 0 51 | end select 52 | 53 | if (keycode = 0) then 54 | '' TODO: unknown scancode - print warning or something 55 | end if 56 | 57 | return keycode 58 | end function 59 | -------------------------------------------------------------------------------- /kernel/src/cpu.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "cpu.bi" 20 | #include "kernel.bi" 21 | #include "mem.bi" 22 | 23 | sub cpu_get_vendor (zstr as zstring ptr) 24 | asm 25 | mov eax, 0 26 | cpuid 27 | mov eax, dword ptr [zstr] 28 | mov dword ptr [eax], ebx 29 | mov dword ptr [eax+4], edx 30 | mov dword ptr [eax+8], ecx 31 | end asm 32 | end sub 33 | 34 | function cpu_has_local_apic () as boolean 35 | dim t_edx as uinteger 36 | asm 37 | mov eax, 1 38 | cpuid 39 | mov dword ptr [t_edx], edx 40 | end asm 41 | 42 | return iif((t_edx and (1 shl 9)), true, false) 43 | end function 44 | 45 | function cpu_supports_PGE () as boolean 46 | dim t_edx as uinteger 47 | asm 48 | mov eax, 1 49 | cpuid 50 | mov dword ptr [t_edx], edx 51 | end asm 52 | 53 | return iif((t_edx and (1 shl 13)), true, false) 54 | end function 55 | 56 | function read_msr (msr as uinteger) as ulongint 57 | dim a as uinteger 58 | dim d as uinteger 59 | 60 | asm 61 | mov ecx, [msr] 62 | 63 | rdmsr 64 | 65 | mov [a], eax 66 | mov [d], edx 67 | end asm 68 | 69 | return (cast(ulongint, d) shl 32) or a 70 | end function 71 | 72 | sub write_msr (msr as uinteger, value as ulongint) 73 | dim a as uinteger = cuint(value) 74 | dim d as uinteger = cuint(value shr 32) 75 | 76 | asm 77 | mov ecx, [msr] 78 | mov eax, [a] 79 | mov edx, [d] 80 | 81 | wrmsr 82 | end asm 83 | end sub 84 | 85 | sub cpu_halt () 86 | asm 87 | cli 88 | hlt_hlt: 89 | hlt 90 | jmp hlt_hlt 91 | end asm 92 | end sub 93 | 94 | sub cpu_disable_interrupts () 95 | asm cli 96 | end sub 97 | -------------------------------------------------------------------------------- /kernel/src/string_tokenizer.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "string_tokenizer.bi" 20 | #include "kmm.bi" 21 | #include "mem.bi" 22 | #include "zstring.bi" 23 | 24 | constructor StringTokenizer (s as zstring ptr) 25 | this.original_string = kmalloc(zstring_len(*s)+1) 26 | memcpy(this.original_string, s, zstring_len(*s)+1) 27 | string_iterator = original_string 28 | end constructor 29 | 30 | destructor StringTokenizer () 31 | if (original_string <> 0) then 32 | kfree(this.original_string) 33 | end if 34 | end destructor 35 | 36 | function StringTokenizer.getToken (delimiters as zstring ptr) as zstring ptr 37 | if string_iterator = 0 then return 0 38 | 39 | '' skip leading delimiters 40 | dim delim_it as ubyte ptr = delimiters 41 | while (*delim_it <> 0 and *string_iterator <> 0) 42 | if (*string_iterator = *delim_it) then 43 | string_iterator += 1 44 | delim_it = delimiters 45 | else 46 | delim_it += 1 47 | end if 48 | wend 49 | 50 | '' did we reach the end of the string already? 51 | if *string_iterator = 0 then return 0 52 | 53 | function = string_iterator 54 | 55 | '' scan for the next delimiter 56 | while (*string_iterator <> 0) 57 | delim_it = delimiters 58 | 59 | while (*delim_it <> 0) 60 | if (*string_iterator = *delim_it) then 61 | '' found delimiter, replace with zero 62 | *cast(byte ptr, string_iterator) = 0 63 | 64 | '' set starting point for next round 65 | string_iterator += 1 66 | 67 | '' done for now 68 | exit function 69 | end if 70 | 71 | delim_it += 1 72 | wend 73 | 74 | string_iterator += 1 75 | wend 76 | 77 | string_iterator = 0 78 | end function 79 | -------------------------------------------------------------------------------- /kernel/src/zstring.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2014 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "zstring.bi" 20 | #include "kernel.bi" 21 | 22 | '' this function searches for the string-terminator (\0) 23 | '' to find out the length of the string 24 | function zstring_len (zstr as zstring) as uinteger 25 | dim counter as uinteger = 0 26 | while (zstr[counter] > 0) 27 | counter += 1 28 | wend 29 | return counter 30 | end function 31 | 32 | '' this is a simple function to find out if and where a string is containing another 33 | function zstring_instr (zstr as zstring, substr as zstring) as uinteger 34 | dim is_substring as boolean 35 | dim len_zstr as uinteger = zstring_len(zstr) 36 | dim len_substr as uinteger = zstring_len(substr) 37 | 38 | if (len_zstr < len_substr) then return 0 39 | 40 | for counter as uinteger = 0 to len_zstr-len_substr 41 | is_substring = true 42 | for substring_length as uinteger = 0 to len_substr-1 43 | if (zstr[counter+substring_length] <> substr[substring_length]) then is_substring = false 44 | next 45 | if (is_substring) then return counter+1 46 | next 47 | 48 | return 0 49 | end function 50 | 51 | function zstring_cmp (zstr1 as zstring, zstr2 as zstring) as integer 52 | dim c as uinteger = 0 53 | while (zstr1[c] = zstr2[c]) 54 | if (zstr1[c] = 0) then return 0 55 | c += 1 56 | wend 57 | 58 | return zstr1[c] - zstr2[c] 59 | end function 60 | 61 | function zstring_ncmp (zstr1 as zstring, zstr2 as zstring, n as uinteger) as integer 62 | dim c as uinteger = 0 63 | 64 | while (c zstr2[c]) then return (zstr1[c] - zstr2[c]) 66 | if (zstr1[c] = 0) then exit while 67 | c += 1 68 | wend 69 | 70 | return 0 71 | end function 72 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/trampoline.asm.embedd: -------------------------------------------------------------------------------- 1 | ; FROST x86 microkernel 2 | ; Copyright (C) 2010-2017 Stefan Schmidt 3 | ; 4 | ; This program is free software: you can redistribute it and/or modify 5 | ; it under the terms of the GNU General Public License as published by 6 | ; the Free Software Foundation, either version 3 of the License, or 7 | ; (at your option) any later version. 8 | ; 9 | ; This program is distributed in the hope that it will be useful, 10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ; GNU General Public License for more details. 13 | ; 14 | ; You should have received a copy of the GNU General Public License 15 | ; along with this program. If not, see . 16 | 17 | ; Code is copied to the first usable page (according to the osdev.org memory map) 18 | org 0x1000 19 | 20 | ; APs start in Real Mode, so 16bit code here 21 | BITS 16 22 | 23 | trampoline_entry: 24 | ; disable interrupts (just to be safe) 25 | cli 26 | 27 | ; load very basic GDT (replaced with a proper one later) 28 | lgdt [simplifiedGDTref] 29 | 30 | ; set Protected Mode bit 31 | mov eax, cr0 32 | or al, 1 33 | mov cr0, eax 34 | 35 | ; jump into Protected Mode 36 | jmp 08h:protectedMode 37 | 38 | simplifiedGDT: 39 | ; null-descriptor 40 | dw 0x0000 41 | dw 0x0000 42 | dw 0x0000 43 | dw 0x0000 44 | 45 | ; code-descriptor 46 | dw 0xFFFF 47 | dw 0x0000 48 | dw 0x9800 49 | dw 0x00CF 50 | 51 | ; data-descriptor 52 | dw 0xFFFF 53 | dw 0x0000 54 | dw 0x9200 55 | dw 0x00CF 56 | 57 | simplifiedGDTref: 58 | dw simplifiedGDTref-simplifiedGDT-1 ; size 59 | dd simplifiedGDT ; start address of the GDT 60 | 61 | 62 | ; Protected Mode code from this point on 63 | BITS 32 64 | 65 | protectedMode: 66 | ; cs is already set by the far jump, set remaining segment registers 67 | mov ax, 0x10 68 | mov ds, ax 69 | mov es, ax 70 | mov fs, ax 71 | mov gs, ax 72 | mov ss, ax 73 | 74 | ; we're free to do whatever we want from here 75 | 76 | ; for now, we print a plus on the serial port 77 | ; doesn't work properly on bochs though, because we don't check if the 78 | ; controller is ready, and boch doesn't like that 79 | mov al, 0x2b 80 | mov dx, 0x03F8 81 | out dx, al 82 | 83 | ; switch on paging here, or in kernel? 84 | ; where do we get a stack from? 85 | ; how do we signal we're ready? 86 | 87 | cli 88 | halt: 89 | hlt 90 | jmp halt 91 | -------------------------------------------------------------------------------- /kernel/src/pmm_dma24.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "pmm.bi" 20 | #include "spinlock.bi" 21 | #include "kernel.bi" 22 | #include "mem.bi" 23 | #include "panic.bi" 24 | 25 | '' NOTE: As long as we just allocate with PAGE_SIZE-granularity, we 26 | '' could use a 'start looking here' pointer to reduce allocation time 27 | 28 | const bits_per_word = sizeof(uinteger)*8 29 | const bitmap_size = 16*1024*1024\PAGE_SIZE\bits_per_word 30 | '' memory bitmap for 0-16MB. 0=used, 1=free 31 | dim shared bitmap (0 to bitmap_size-1) as uinteger 32 | dim shared pmm_dma24_lock as spinlock 33 | 34 | 35 | sub pmm_init_dma24 () 36 | '' mark the whole memory as occupied 37 | memset(@bitmap(0), 0, bitmap_size*sizeof(uinteger)) 38 | end sub 39 | 40 | function pmm_alloc_dma24 () as any ptr 41 | pmm_dma24_lock.acquire() 42 | 43 | for counter as uinteger = lbound(bitmap) to ubound(bitmap) 44 | if (bitmap(counter) = 0) then continue for 45 | 46 | for bitcounter as uinteger = 0 to bits_per_word-1 47 | if (bitmap(counter) and (1 shl bitcounter)) then 48 | '' this page is free 49 | '' mark used 50 | bitmap(counter) and= (not(1 shl bitcounter)) 51 | '' return page address 52 | pmm_dma24_lock.release() 53 | return cast(any ptr, (counter*bits_per_word + bitcounter)*PAGE_SIZE) 54 | end if 55 | next 56 | next 57 | 58 | '' no free page found? 59 | pmm_dma24_lock.release() 60 | panic_error(!"PMM_DMA24: Out of memory!\n") 61 | return nullptr 62 | end function 63 | 64 | sub pmm_free_dma24 (page as any ptr) 65 | pmm_dma24_lock.acquire() 66 | 67 | dim p as uinteger = cuint(page) \ PAGE_SIZE 68 | 69 | dim index as uinteger = p \ bits_per_word 70 | dim modifier as uinteger = (1 shl (p mod bits_per_word)) 71 | 72 | assert((bitmap(index) and modifier) = 0) '' make sure that the page really was occupied 73 | 74 | bitmap(index) or= modifier 75 | 76 | pmm_dma24_lock.release() 77 | end sub 78 | -------------------------------------------------------------------------------- /kernel/src/process.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "process.bi" 20 | #include "pmm.bi" 21 | #include "isf.bi" 22 | #include "vmm.bi" 23 | #include "kmm.bi" 24 | #include "mem.bi" 25 | #include "elf32.bi" 26 | #include "video.bi" 27 | #include "kernel.bi" 28 | #include "spinlock.bi" 29 | #include "panic.bi" 30 | 31 | DEFINE_LIST(process_type) 32 | 33 | function generate_pid () as uinteger 34 | static next_pid as uinteger = 0 '' next process id to assign 35 | static pid_lock as spinlock '' spinlock to protect concurrent access 36 | 37 | dim pid as uinteger '' the generated pid 38 | 39 | pid_lock.acquire() '' acquire lock 40 | pid = next_pid '' save pid 41 | next_pid += 1 '' increase pid counter 42 | pid_lock.release() '' release lock 43 | 44 | return pid '' return generated pid 45 | end function 46 | 47 | dim shared processlist as Listtype(process_type) 48 | 49 | operator process_type.new (size as uinteger) as any ptr 50 | return kmalloc(size) 51 | '' constructor is called automatically 52 | end operator 53 | 54 | operator process_type.delete (buffer as any ptr) 55 | kfree(buffer) 56 | '' destructor is called automatically 57 | end operator 58 | 59 | constructor process_type (parent as process_type ptr = 0) 60 | '' assign a process-ID 61 | this.id = generate_pid() 62 | 63 | '' set parent 64 | this.parent = parent 65 | 66 | this.ipc_handler = nullptr 67 | this.io_bitmap = nullptr 68 | 69 | '' insert the process into the list 70 | processlist.insert_before(@this.process_list) 71 | 72 | '' create a vmm-context 73 | vmm_context_initialize(@this.context) 74 | end constructor 75 | 76 | function process_type.get_tid () as uinteger 77 | this.tid_lock.acquire() 78 | 79 | function = this.next_tid 80 | this.next_tid += 1 81 | 82 | this.tid_lock.release() 83 | end function 84 | 85 | sub process_remove_thread (thread as thread_type ptr) 86 | thread->process_threads.remove() 87 | end sub 88 | -------------------------------------------------------------------------------- /kernel/include/smp.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | type smp_floating_pointer field=1 22 | signature as uinteger 23 | config_table as uinteger 24 | length as ubyte 25 | version as ubyte 26 | checksum as ubyte 27 | features(0 to 4) as ubyte 28 | end type 29 | 30 | type smp_config_table field=1 31 | signature as uinteger 32 | base_table_length as ushort 33 | spec_revision as ubyte 34 | checksum as ubyte 35 | oem_id as zstring*8 36 | product_id as zstring*12 37 | oem_table_ptr as uinteger 38 | oem_table_size as ushort 39 | entry_count as ushort 40 | local_apic_address as uinteger 41 | 42 | extended_table_length as ushort 43 | extended_table_checksum as ubyte 44 | reserved as ubyte 45 | end type 46 | 47 | enum CT_ENTRY_TYPES explicit 48 | PROCESSOR = 0 49 | BUS = 1 50 | IO_APIC = 2 51 | IO_INTERRUPT_ASSIGNMENT = 3 52 | LOCAL_INTERRUPT_ASSIGNMENT = 4 53 | end enum 54 | 55 | 56 | type cte_processor field=1 57 | entry_type as ubyte 58 | local_apic_id as ubyte 59 | local_apic_version as ubyte 60 | flags as ubyte 61 | signature as zstring*4 62 | feature_flags as uinteger 63 | reserved as ulongint 64 | end type 65 | 66 | type cte_bus field=1 67 | entry_type as ubyte 68 | bus_id as ubyte 69 | type_string as zstring*6 70 | end type 71 | 72 | type cte_io_apic field=1 73 | entry_type as ubyte 74 | id as ubyte 75 | version as ubyte 76 | flags as ubyte 77 | address as uinteger 78 | end type 79 | 80 | type cte_io_interrupt_assignment field=1 81 | entry_type as ubyte 82 | interrupt_type as ubyte 83 | flags as ushort 84 | bus_id as ubyte 85 | bus_irq as ubyte 86 | apic_id as ubyte 87 | apic_int as ubyte 88 | end type 89 | 90 | type cte_local_interrupt_assignment field=1 91 | entry_type as ubyte 92 | interrupt_type as ubyte 93 | flags as ushort 94 | bus_id as ubyte 95 | bus_irq as ubyte 96 | apic_id as ubyte 97 | apic_int as ubyte 98 | end type 99 | 100 | declare sub smp_init () 101 | -------------------------------------------------------------------------------- /kernel/include/vfs.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "kernel.bi" 22 | #include "intrusive_list.bi" 23 | #include "kmm.bi" 24 | #include "refcount_smartptr.bi" 25 | #include "uid128.bi" 26 | 27 | const VFS_FLAGS_KERNEL_NODE as integer = &h1 28 | 29 | type vfs_node as vfs_node_ 30 | type __process_type as process_type 31 | type __thread_type as thread_type 32 | 33 | DECLARE_REFCOUNTPTR(vfs_node) 34 | DECLARE_LIST(vfs_node) 35 | 36 | type vfs_node_ extends RefCounted 37 | name as zstring ptr 38 | 39 | flags as integer 40 | permissions as integer 41 | 42 | uid as integer 43 | gid as integer 44 | 45 | union 46 | type 47 | owner as __process_type ptr 48 | handler as any ptr 49 | node_uid as uinteger 50 | end type 51 | 52 | mem as any ptr 53 | end union 54 | 55 | parent as vfs_node ptr 56 | child_list as Listtype(vfs_node) 57 | node_list as Listtype(vfs_node) = Listtype(vfs_node)(offsetof(vfs_node_, node_list)) 58 | 59 | declare operator new (size as uinteger) as any ptr 60 | declare operator delete (buffer as any ptr) 61 | declare constructor (name as zstring ptr, parent as vfs_node ptr, flags as integer, owner as __process_type ptr = nullptr) 62 | 63 | declare function getChildByName (name as zstring) as RefCountPtr(vfs_node) 64 | end type 65 | 66 | DECLARE_LIST(vfs_fd) 67 | type vfs_fd 68 | id as uid128 69 | seekptr as uinteger<64> 70 | node as RefCountPtr(vfs_node) 71 | 72 | fd_list as Listtype(vfs_fd) = Listtype(vfs_fd)(offsetof(vfs_fd, fd_list)) 73 | 74 | declare operator new (size as uinteger) as any ptr 75 | declare operator delete (buffer as any ptr) 76 | declare constructor (process as __process_type ptr, node as RefCountPtr(vfs_node)) 77 | end type 78 | 79 | declare sub vfs_init () 80 | declare function vfs_get_root as RefCountPtr(vfs_node) 81 | declare function vfs_parse_path (path as zstring) as RefCountPtr(vfs_node) 82 | declare function vfs_parse_path_afap (path as zstring) as RefCountPtr(vfs_node) 83 | declare function vfs_create (path as zstring ptr, name_ as zstring ptr, owner as __process_type ptr) as RefCountPtr(vfs_node) 84 | declare function vfs_open (thread as __thread_type ptr, path as zstring ptr, flags as uinteger) as vfs_fd ptr 85 | -------------------------------------------------------------------------------- /kernel/src/pic.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "pic.bi" 20 | #include "in_out.bi" 21 | #include "kernel.bi" 22 | 23 | const MASTER_COMMAND as ubyte = &h20 24 | const MASTER_DATA as ubyte = &h21 25 | const SLAVE_COMMAND as ubyte = &hA0 26 | const SLAVE_DATA as ubyte = &hA1 27 | 28 | '' the end-of-interrupt command: 29 | const COMMAND_EOI as ubyte = &h20 30 | 31 | sub pic_init () 32 | '' send ICW1 to both pics 33 | outb(MASTER_COMMAND, &h11) 34 | outb(SLAVE_COMMAND, &h11) 35 | 36 | '' ICW2 is where we want to map the interrupts 37 | '' we map them directly after the exceptions 38 | outb(MASTER_DATA, &h20) 39 | outb(SLAVE_DATA, &h28) 40 | 41 | '' ICW3: tell the PICs that they're connected through IRQ 2 42 | outb(MASTER_DATA, &h04) 43 | outb(SLAVE_DATA, &h02) 44 | 45 | '' ICW4: tell the PICs we're in 8086-mode 46 | outb(MASTER_DATA, &h01) 47 | outb(SLAVE_DATA, &h01) 48 | 49 | '' select ISR 50 | outb(MASTER_COMMAND, &h0B) 51 | outb(SLAVE_COMMAND, &h0B) 52 | end sub 53 | 54 | sub pic_send_eoi (irq as ubyte) 55 | outb(MASTER_COMMAND, COMMAND_EOI) '' send the EOI-command to the first PIC 56 | if (irq>7) then outb(SLAVE_COMMAND, COMMAND_EOI) '' if the irq was above 7, the second PIC needs to be informed also 57 | end sub 58 | 59 | function pic_is_spurious (irq as ubyte) as boolean 60 | if (irq = 7) then 61 | '' check ISR of the first pic 62 | if ((inb(MASTER_COMMAND) and &b10000000) = 0) then return true 63 | elseif (irq = 15) then 64 | '' check ISR of the second pic 65 | if ((inb(SLAVE_COMMAND) and &b10000000) = 0) then return true 66 | end if 67 | 68 | return false 69 | end function 70 | 71 | sub pic_mask (irq as ubyte) 72 | dim port as ushort 73 | 74 | if (irq < 8) then 75 | port = MASTER_DATA 76 | else 77 | port = SLAVE_DATA 78 | irq -= 8 79 | end if 80 | 81 | outb(port, (inb(port) or (1 shl irq))) 82 | end sub 83 | 84 | sub pic_mask_all () 85 | outb(MASTER_DATA, &hFF) 86 | outb(SLAVE_DATA, &hFF) 87 | end sub 88 | 89 | sub pic_unmask (irq as ubyte) 90 | dim port as ushort 91 | 92 | if (irq < 8) then 93 | port = MASTER_DATA 94 | else 95 | port = SLAVE_DATA 96 | irq -= 8 97 | end if 98 | 99 | outb(port, (inb(port) and not(1 shl irq))) 100 | end sub 101 | -------------------------------------------------------------------------------- /kernel/src/pmm_normal.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "pmm.bi" 20 | #include "spinlock.bi" 21 | #include "kernel.bi" 22 | #include "vmm.bi" 23 | #include "panic.bi" 24 | 25 | dim shared pmm_normal_lock as spinlock 26 | 27 | dim shared pmm_stack_min as uinteger ptr = cast(uinteger ptr, PMM_STACK_TOP) 28 | dim shared pmm_stack_ptr as uinteger ptr = cast(uinteger ptr, PMM_STACK_TOP) 29 | dim shared pmm_ready as boolean = false 30 | 31 | function pmm_alloc_normal () as any ptr 32 | if (not (pmm_ready and vmm_is_paging_ready())) then return nullptr '' let the request fall through 33 | 34 | if (pmm_stack_ptr = PMM_STACK_TOP) then return nullptr 35 | 36 | pmm_normal_lock.acquire() 37 | 38 | if (pmm_stack_ptr = (pmm_stack_min + PMM_STACK_ENTRIES_PER_PAGE)) then 39 | '' resolve page address 40 | function = vmm_resolve(vmm_get_current_context(), pmm_stack_min) 41 | 42 | '' unmap page 43 | vmm_unmap_page(vmm_get_current_context(), pmm_stack_min) 44 | 45 | '' adjust stack size 46 | pmm_stack_min += PMM_STACK_ENTRIES_PER_PAGE 47 | else 48 | if (vmm_is_paging_activated()) then 49 | function = cast(any ptr, *pmm_stack_ptr) 50 | else 51 | dim pmm_stack_ptr_phys as uinteger ptr = vmm_resolve(vmm_get_current_context(), pmm_stack_ptr) 52 | function = cast(any ptr, *pmm_stack_ptr_phys) 53 | end if 54 | pmm_stack_ptr += 1 55 | end if 56 | 57 | pmm_normal_lock.release() 58 | end function 59 | 60 | sub pmm_free_normal (addr as any ptr) 61 | '' make sure the address is page-aligned 62 | addr = cast(any ptr, cuint(addr) and VMM_PAGE_MASK) 63 | 64 | pmm_normal_lock.acquire() 65 | 66 | '' stack full? 67 | if (pmm_stack_ptr = pmm_stack_min) then 68 | vmm_map_page(vmm_get_current_context(), pmm_stack_min-PMM_STACK_ENTRIES_PER_PAGE, addr, VMM_FLAGS.KERNEL_DATA) 69 | pmm_stack_min -= PMM_STACK_ENTRIES_PER_PAGE 70 | assert(vmm_resolve(vmm_get_current_context(), pmm_stack_min) <> nullptr) 71 | else 72 | '' put the page on the stack 73 | pmm_stack_ptr -= 1 74 | 75 | if (vmm_is_paging_activated()) then 76 | *pmm_stack_ptr = cuint(addr) 77 | else 78 | dim pmm_stack_ptr_phys as uinteger ptr = vmm_resolve(vmm_get_current_context(), pmm_stack_ptr) 79 | assert(pmm_stack_ptr_phys <> nullptr) 80 | *pmm_stack_ptr_phys = cuint(addr) 81 | end if 82 | end if 83 | 84 | pmm_ready = true 85 | 86 | pmm_normal_lock.release() 87 | end sub 88 | -------------------------------------------------------------------------------- /kernel/include/refcount_smartptr.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "atomic.bi" 22 | 23 | type RefCounted 24 | dim refcount as AtomicInt 25 | end type 26 | 27 | 28 | #define RefCountPtr(T_) RefCountPtr_##T_ 29 | 30 | #macro DECLARE_REFCOUNTPTR(T_) 31 | type RefCountPtr(T_) 32 | ref as T_ ptr 33 | 34 | declare constructor () 35 | 36 | '' construct from raw pointer 37 | declare constructor (reference as T_ ptr) 38 | 39 | '' copy-constructor 40 | declare constructor (reference as RefCountPtr(T_)) 41 | 42 | '' clean-up destructor 43 | declare destructor () 44 | 45 | declare operator let (byref rhs as RefCountPtr(T_)) 46 | 47 | declare function get_count () as integer 48 | end type 49 | #endmacro 50 | 51 | #macro DEFINE_REFCOUNTPTR(T_) 52 | operator -> (byref tt_ as RefCountPtr(T_)) byref as T_ 53 | assert(tt_.ref <> 0) 54 | return *tt_.ref 55 | end operator 56 | 57 | operator = (byref tt_ as RefCountPtr(T_), byref tt2_ as RefCountPtr(T_)) as integer 58 | if (tt_.ref = tt2_.ref) then return -1 59 | return 0 60 | end operator 61 | 62 | constructor RefCountPtr(T_) () 63 | this.ref = 0 64 | end constructor 65 | 66 | constructor RefCountPtr(T_) (reference as T_ ptr) 67 | assert(reference <> 0) 68 | reference->refcount.inc() 69 | this.ref = reference 70 | end constructor 71 | 72 | constructor RefCountPtr(T_) (reference as RefCountPtr(T_)) 73 | assert(reference.ref <> 0) 74 | reference.ref->refcount.inc() 75 | this.ref = reference.ref 76 | end constructor 77 | 78 | destructor RefCountPtr(T_) () 79 | dim destroy as boolean = this.ref->refcount.sub_and_test(1) 80 | 81 | if (destroy) then 82 | delete this.ref 83 | end if 84 | end destructor 85 | 86 | operator RefCountPtr(T_).let (byref rhs as RefCountPtr(T_)) 87 | if (this.ref <> 0) then 88 | dim destroy as boolean = this.ref->refcount.sub_and_test(1) 89 | 90 | if (destroy) then 91 | delete this.ref 92 | end if 93 | end if 94 | 95 | rhs.ref->refcount.inc() 96 | this.ref = rhs.ref 97 | end operator 98 | 99 | 100 | function RefCountPtr(T_).get_count () as integer 101 | return this.ref->refcount.get() 102 | end function 103 | #endmacro 104 | -------------------------------------------------------------------------------- /kernel/include/thread.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "isf.bi" 22 | #include "intrusive_list.bi" 23 | #include "address_space.bi" 24 | 25 | const THREAD_STATE_DISABLED = 0 26 | const THREAD_STATE_RUNNING = 1 27 | const THREAD_STATE_BLOCKED = 2 28 | const THREAD_STATE_KILL_ON_SCHEDULE = 3 29 | 30 | const THREAD_FLAG_POPUP = 1 31 | const THREAD_FLAG_RESCHEDULE = 2 32 | const THREAD_FLAG_TRIGGERS_CALLBACK = 4 33 | 34 | DECLARE_LIST(thread_type) 35 | 36 | type process_type_ as process_type 37 | 38 | '' FIXME: what if process that requested the callback exits in the meantime? We would break this code! 39 | '' - making processes reference-counted would be an option 40 | '' - or maybe a 'callbacks-pending' variable that gets checked before destruction? 41 | '' FIXME: also, how do we make sure the callback always gets triggered, even when the popup-thread misbehaves? 42 | type callback_info_t 43 | process as process_type_ ptr '*< the process which receives the callback 44 | handle as uinteger '*< a caller-defined handle which gets passed to the callback 45 | callback as any ptr '*< the address of a function that gets called as a callback 46 | end type 47 | 48 | type thread_type 49 | parent_process as process_type_ ptr 50 | 51 | id as uinteger 52 | flags as uinteger 53 | state as uinteger 54 | 55 | kernelstack_p as any ptr 56 | kernelstack_bottom as any ptr 57 | stack_area as address_space_area ptr 58 | isf as interrupt_stack_frame ptr 59 | 60 | '' list of threads of a process 61 | process_threads as Listtype(thread_type) = Listtype(thread_type)(offsetof(thread_type, process_threads)) 62 | 63 | '' list of active threads 64 | active_threads as Listtype(thread_type) = Listtype(thread_type)(offsetof(thread_type, active_threads)) 65 | 66 | declare operator new (size as uinteger) as any ptr 67 | declare operator new[] (size as uinteger) as any ptr 68 | declare operator delete (buffer as any ptr) 69 | 70 | declare constructor (process as process_type_ ptr, entry as any ptr, userstack_pages as uinteger, flags as ubyte = 0) 71 | declare sub activate () 72 | declare sub deactivate () 73 | declare sub destroy () 74 | 75 | callback_info as callback_info_t 76 | 77 | end type 78 | 79 | declare function schedule (isf as interrupt_stack_frame ptr) as thread_type ptr 80 | declare sub thread_switch (isf as interrupt_stack_frame ptr) 81 | declare function get_current_thread () as thread_type ptr 82 | declare sub thread_create_idle_thread () 83 | declare sub set_io_bitmap () 84 | -------------------------------------------------------------------------------- /kernel/src/debug.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "debug.bi" 20 | #include "kernel.bi" 21 | #include "video.bi" 22 | #include "in_out.bi" 23 | 24 | 25 | '' this function allows a loglevel to be set which is used by a wrapper for the video-code 26 | sub debug_set_loglevel (level as ubyte) 27 | debug_loglevel = level 28 | end sub 29 | 30 | #if defined (FROST_DEBUG) 31 | dim shared debug_com_initialized as boolean = false 32 | dim shared COM1_PORT as ushort = &h3F8 33 | 34 | const REG_IER as ushort = 1 '' [RW] Interrupt Enable Register 35 | const REG_IIR as ushort = 2 '' [R ] Interrupt Identification Register 36 | const REG_FCR as ushort = 2 '' [ W] FIFO Control Register 37 | const REG_LCR as ushort = 3 '' [RW] Line Control Register 38 | const REG_MCR as ushort = 4 '' [RW] Modem Control Register 39 | const REG_LSR as ushort = 5 '' [R ] Line Status Register 40 | const REG_MSR as ushort = 6 '' [R ] Modem Status Register 41 | const REG_SCR as ushort = 7 '' [RW] Scratch Register 42 | 43 | sub debug_init_com (baud as uinteger, parity as ubyte, bits as ubyte) 44 | dim divisor as ushort = 115200\baud 45 | 46 | '' DLAB=1 47 | outb(COM1_PORT+REG_LCR, &h80) 48 | 49 | '' set baud rate divisor 50 | outb(COM1_PORT, lobyte(divisor)) 51 | outb(COM1_PORT+REG_IER, hibyte(divisor)) 52 | 53 | '' set parity, bits-per-byte and DLAB=0 54 | outb(COM1_PORT+REG_LCR, ((parity and &h07) shl 3) or ((bits-5) and &h03)) 55 | 56 | '' no interrupts 57 | outb(COM1_PORT+REG_IER, 0) 58 | 59 | '' disable FIFOs 60 | outb(COM1_PORT+REG_FCR, &h00) 61 | 62 | '' disable AUX & loopback 63 | outb(COM1_PORT+REG_MCR, &h00) 64 | end sub 65 | 66 | sub debug_serial_init () 67 | debug_init_com(19200, 0, 8) 68 | debug_com_initialized = true 69 | end sub 70 | 71 | sub debug_serial_putc (char as ubyte) 72 | '' typical terminal software requires a carriage return, too 73 | if (char = 10) then 74 | debug_serial_putc(13) 75 | end if 76 | 77 | if (debug_com_initialized) then 78 | '' wait until we can write 79 | while((inb(COM1_PORT+REG_LSR) and &h20) = 0) : wend 80 | '' write byte 81 | outb(COM1_PORT, char) 82 | end if 83 | end sub 84 | #endif 85 | 86 | sub debug_stacktrace (maxFrames as uinteger) 87 | dim ebp as uinteger ptr = @maxFrames -2 88 | 89 | ebp = cast(uinteger ptr, ebp) 90 | 91 | printk(LOG_ERR !"stacktrace\n") 92 | for frame as uinteger = 0 to maxFrames 93 | dim eip as uinteger = ebp[1] 94 | 95 | if (eip = 0) or (ebp = nullptr) then 96 | exit for 97 | end if 98 | 99 | ebp = cast(uinteger ptr, ebp[0]) 100 | printk(LOG_ERR !" 0x%08X\n", eip) 101 | next 102 | end sub 103 | -------------------------------------------------------------------------------- /kernel/src/io_man.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "kernel.bi" 20 | #include "process.bi" 21 | #include "kmm.bi" 22 | #include "mem.bi" 23 | #include "video.bi" 24 | 25 | dim shared global_port_bitmap(0 to 2047) as uinteger 26 | 27 | sub init_ports () 28 | asm 29 | pushf 30 | pop eax 31 | and eax, &hFFFFCFFF 32 | push eax 33 | popf 34 | end asm 35 | 36 | memset(@global_port_bitmap(0), 0, sizeof(uinteger)*2048) 37 | end sub 38 | 39 | function request_port (process as process_type ptr, port as uinteger) as boolean 40 | dim index as uinteger = port \ 32 41 | dim mask as uinteger = 1 shl (port mod 32) 42 | 43 | '' port out of range? 44 | if (port >= &hFFFF) then 45 | return false 46 | end if 47 | 48 | '' port free ? 49 | if (global_port_bitmap(index) and mask) then 50 | '' port not reserved for this process? 51 | if ((process->io_bitmap <> nullptr) and process->io_bitmap[index] and mask) then 52 | return false 53 | else 54 | return true 55 | end if 56 | end if 57 | 58 | '' if there is no bitmap yet, reserve one 59 | if (process->io_bitmap = nullptr) then 60 | process->io_bitmap = kmalloc(&hFFFF \ 8) 61 | memset(process->io_bitmap, &hFF, &hFFFF \ 8) 62 | end if 63 | 64 | '' reserve the port 65 | global_port_bitmap(index) or= mask 66 | process->io_bitmap[index] and= not mask 67 | 68 | return true 69 | end function 70 | 71 | function release_port (process as process_type ptr, port as uinteger) as boolean 72 | dim index as uinteger = port \ 32 73 | dim mask as uinteger = 1 shl (port mod 32) 74 | 75 | if (process->io_bitmap = nullptr) then return false 76 | 77 | if (process->io_bitmap[index] and mask) then return false 78 | 79 | assert((global_port_bitmap(index) and mask) > 0) 80 | 81 | global_port_bitmap(index) and= not mask 82 | process->io_bitmap[index] or= mask 83 | 84 | return true 85 | end function 86 | 87 | function request_port_range (process as process_type ptr, start_port as uinteger, length as uinteger) as boolean 88 | for port_counter as uinteger = start_port to start_port+length 89 | if (not request_port(process, port_counter)) then 90 | for port_counter2 as uinteger = port_counter to start_port step -1 91 | release_port(process, port_counter2) 92 | return false 93 | next 94 | end if 95 | next 96 | 97 | return true 98 | end function 99 | 100 | function release_port_range (process as process_type ptr, start_port as uinteger, length as uinteger) as boolean 101 | function=true 102 | for port_counter as uinteger = start_port to start_port+length 103 | if (not release_port(process, port_counter)) then function=false 104 | next 105 | end function 106 | -------------------------------------------------------------------------------- /kernel/src/stubs.asm: -------------------------------------------------------------------------------- 1 | ; FROST x86 microkernel 2 | ; Copyright (C) 2010-2017 Stefan Schmidt 3 | ; 4 | ; This program is free software: you can redistribute it and/or modify 5 | ; it under the terms of the GNU General Public License as published by 6 | ; the Free Software Foundation, either version 3 of the License, or 7 | ; (at your option) any later version. 8 | ; 9 | ; This program is distributed in the hope that it will be useful, 10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ; GNU General Public License for more details. 13 | ; 14 | ; You should have received a copy of the GNU General Public License 15 | ; along with this program. If not, see . 16 | 17 | ; This file is to provide stubs for the exceptions and irqs 18 | ; which then call the interrupt handler of the kernel 19 | section .text 20 | 21 | extern HANDLE_INTERRUPT 22 | 23 | ; some ints push a errorcode on the stack 24 | ; the handler for ints which do not do that pushes a zero to the stack to make the stack look equal 25 | %macro int_stub 1 26 | global INT_STUB_%1 27 | INT_STUB_%1: 28 | %if (%1 != 8) && (%1 < 10 || %1 > 14) && (%1 != 17) 29 | push dword 0 30 | %endif 31 | push dword %1 32 | jmp int_common 33 | %endmacro 34 | 35 | ; create all 256 stubs (0-255) 36 | %assign stub_counter 0 37 | %rep 256 38 | int_stub stub_counter 39 | %assign stub_counter stub_counter+1 40 | %endrep 41 | 42 | extern HANDLE_INTERRUPT 43 | global SYSENTER_ENTRY 44 | 45 | int_common: 46 | ; save the registers 47 | push ebp 48 | push edi 49 | push esi 50 | push edx 51 | push ecx 52 | push ebx 53 | push eax 54 | 55 | ; load the ring-0 segment-registers 56 | mov ax, 0x10 57 | mov ds, ax 58 | mov es, ax 59 | 60 | push dword 0 61 | 62 | ; now call the handler 63 | push esp ; push the old stack address 64 | call HANDLE_INTERRUPT ; call the interrupt-handler written in FreeBASIC 65 | mov esp, eax ; set the new stack address 66 | 67 | pop ebx 68 | test ebx, ebx 69 | jne SYSENTER_EXIT 70 | 71 | int_exit: 72 | ; load the ring-3 segment-registers 73 | mov ax, 0x23 74 | mov ds, ax 75 | mov es, ax 76 | 77 | ; restore the old state 78 | pop eax 79 | pop ebx 80 | pop ecx 81 | pop edx 82 | pop esi 83 | pop edi 84 | pop ebp 85 | 86 | ; skip the errorcode and the interrupt-number 87 | add esp, 8 88 | 89 | ; now we return 90 | iret 91 | 92 | 93 | section .text 94 | SYSENTER_ENTRY: 95 | ; We make the stack look like an x86 interrupt-stackframe 96 | sub esp, 24 97 | push dword 0xFF 98 | 99 | push ebp 100 | push edi 101 | push esi 102 | push edx 103 | push ecx 104 | push ebx 105 | push eax 106 | 107 | push dword 1 108 | 109 | push esp 110 | call HANDLE_INTERRUPT 111 | mov esp, eax 112 | 113 | pop ebx 114 | test ebx, ebx 115 | je int_exit 116 | 117 | SYSENTER_EXIT: 118 | pop eax 119 | pop ebx 120 | pop ecx 121 | pop edx 122 | pop esi 123 | pop edi 124 | pop ebp 125 | 126 | add esp, 28 127 | 128 | ; SYSENTER clears the interrupt-flag in EFLAGS without saving, 129 | ; so we set it again with sti. sti has a delay of one instruction, 130 | ; so it's impossible we get interrupted before sysexit. 131 | sti 132 | sysexit 133 | -------------------------------------------------------------------------------- /kernel/include/vmm.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #include "kernel.bi" 22 | 23 | #define num_pages(n) (((n + &hFFF) and (&hFFFFF000)) shr 12) 24 | 25 | '' flags for page-table-entries 26 | enum VMM_PTE_FLAGS explicit 27 | PRESENT = &h1 28 | WRITABLE = &h2 29 | USERSPACE = &h4 30 | WRITETHROUGH = &h8 31 | NOT_CACHEABLE = &h10 32 | ACCESSED = &h20 33 | DIRTY = &h40 34 | PAT = &h80 35 | GLOBAL = &h100 36 | end enum 37 | 38 | '' flags for page-directory-entries 39 | enum VMM_PDE_FLAGS explicit 40 | PRESENT = &h1 41 | WRITABLE = &h2 42 | USERSPACE = &h4 43 | WRITETHROUGH = &h8 44 | NOT_CACHEABLE = &h10 45 | ACCESSED = &h20 46 | DIRTY = &h40 47 | FOUR_MB = &h80 48 | GLOBAL = &h100 49 | end enum 50 | 51 | enum VMM_FLAGS explicit 52 | USER_DATA = VMM_PTE_FLAGS.PRESENT or VMM_PTE_FLAGS.WRITABLE or VMM_PTE_FLAGS.USERSPACE 53 | KERNEL_DATA = VMM_PTE_FLAGS.PRESENT or VMM_PTE_FLAGS.WRITABLE or VMM_PTE_FLAGS.GLOBAL 54 | end enum 55 | 56 | '' the kernels address space is from 0-1 gb, so we put the kernels pagetables at 1gb-4mb 57 | const VMM_PAGETABLES_VIRT_START as uinteger = &h3FC00000 58 | const VMM_PAGE_MASK as uinteger = &hFFFFF000 59 | 60 | type vmm_context 61 | version as uinteger '' important to keep the kernel section up to date 62 | p_pagedir as uinteger ptr '' physical address of the pagedir, needed for the cpu 63 | v_pagedir as uinteger ptr '' virtual address of the pagedir, needed to access the pagedir later 64 | end type 65 | 66 | declare sub vmm_init () 67 | declare sub vmm_init_local () 68 | declare function vmm_alloc (v_addr as any ptr) as boolean 69 | declare sub vmm_context_initialize (cntxt as vmm_context ptr) 70 | declare function vmm_map_page (cntxt as vmm_context ptr, virtual as any ptr, physical as any ptr, flags as uinteger) as boolean 71 | declare sub vmm_unmap_page (cntxt as vmm_context ptr, v_addr as any ptr) 72 | declare function vmm_map_range (cntxt as vmm_context ptr, v_addr as any ptr, p_start as any ptr, p_end as any ptr, flags as uinteger) as boolean 73 | declare sub vmm_unmap_range (cntxt as vmm_context ptr, v_addr as any ptr, pages as uinteger) 74 | declare function vmm_automap (context as vmm_context ptr, p_start as any ptr, size as uinteger, lowerLimit as uinteger, upperLimit as uinteger, flags as uinteger) as any ptr 75 | declare function vmm_kernel_automap (p_start as any ptr, size as uinteger, flags as uinteger = VMM_FLAGS.KERNEL_DATA) as any ptr 76 | declare sub vmm_kernel_unmap (v_start as any ptr, size as uinteger) 77 | declare function vmm_resolve (cntxt as vmm_context ptr, vaddr as any ptr) as any ptr 78 | declare sub vmm_activate_context (cntxt as vmm_context ptr) 79 | declare function vmm_get_current_context () as vmm_context ptr 80 | declare function vmm_is_paging_activated () as boolean 81 | declare function vmm_is_paging_ready () as boolean 82 | -------------------------------------------------------------------------------- /kernel/src/interrupt.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "apic.bi" 20 | #include "pic.bi" 21 | #include "cpu.bi" 22 | #include "interrupt.bi" 23 | 24 | dim shared legacy_mode as boolean = true 25 | dim shared interrupt_legacy_free as boolean = false 26 | 27 | sub interrupt_init () 28 | if (cpu_has_local_apic()) then 29 | legacy_mode = false 30 | 31 | '' the ACPI-code sets this variable when the 8259-PIC-flag in the MADT is not set 32 | if (not interrupt_legacy_free) then 33 | pic_init() 34 | pic_mask_all() 35 | end if 36 | 37 | lapic_init() 38 | ioapic_init() 39 | return 40 | end if 41 | 42 | pic_init() 43 | pic_mask_all() 44 | end sub 45 | 46 | sub interrupt_mask (interrupt as integer) 47 | if (legacy_mode) then 48 | '' ignore non-IRQs 49 | if ((interrupt < &h20) or (interrupt > &h2F)) then return 50 | 51 | pic_mask(interrupt - &h20) 52 | return 53 | end if 54 | 55 | if (interrupt < &h20) then return 56 | ioapic_mask_irq(interrupt-&h20) 57 | end sub 58 | 59 | sub interrupt_unmask (interrupt as integer) 60 | if (legacy_mode) then 61 | '' ignore non-IRQs 62 | if ((interrupt < &h20) or (interrupt > &h2F)) then return 63 | 64 | pic_unmask(interrupt - &h20) 65 | return 66 | end if 67 | 68 | if (interrupt < &h20) then return 69 | ioapic_unmask_irq(interrupt-&h20) 70 | end sub 71 | 72 | function interrupt_is_spurious (interrupt as integer) as boolean 73 | if (legacy_mode) then 74 | '' ignore non-IRQs 75 | if ((interrupt < &h20) or (interrupt > &h2F)) then return false 76 | 77 | return pic_is_spurious(interrupt - &h20) 78 | end if 79 | 80 | '' is it a spurios I/O APIC interrupt? 81 | if (interrupt = &h2F) then return true 82 | 83 | '' could still be a spurious PIC-interrupt 84 | if (not interrupt_legacy_free) then return pic_is_spurious(interrupt - &h20) 85 | 86 | return false 87 | end function 88 | 89 | sub interrupt_eoi (interrupt as integer) 90 | if (legacy_mode) then 91 | '' ignore non-IRQs 92 | if ((interrupt < &h20) or (interrupt > &h2F)) then return 93 | 94 | if (interrupt_is_spurious(interrupt)) then 95 | '' did it come from the slave PIC? then send EOI to the master 96 | if (interrupt = &h2F) then pic_send_eoi(&h01) 97 | return 98 | end if 99 | 100 | pic_send_eoi(interrupt - &h20) 101 | return 102 | end if 103 | 104 | '' Volume 3A Chapter 10.9 says we shouldn't send the LAPIC an EOI when receiving a spurious interrupt 105 | '' also, since we don't need the PIC to get IRQs, we just ignore its spurious interrupts and send no EOI to it ever 106 | if (not(interrupt_is_spurious(interrupt))) then 107 | lapic_eoi() 108 | end if 109 | end sub 110 | -------------------------------------------------------------------------------- /kernel/src/address_space.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "address_space.bi" 20 | #include "pmm.bi" 21 | #include "kmm.bi" 22 | #include "video.bi" 23 | 24 | DEFINE_LIST(address_space_area) 25 | 26 | constructor address_space_area (address as any ptr, pages as uinteger, flags as uinteger = 0, description as zstring ptr = nullptr) 27 | this.address = address 28 | this.pages = pages 29 | this.flags = flags 30 | this.description = description 31 | end constructor 32 | 33 | operator address_space_area.new (size as uinteger) as any ptr 34 | return kmalloc(size) 35 | end operator 36 | 37 | operator address_space_area.delete (buffer as any ptr) 38 | kfree(buffer) 39 | end operator 40 | 41 | function address_space.allocate_area (pages as uinteger, flags as uinteger = 0, description as zstring ptr = nullptr) as address_space_area ptr 42 | '' 1. search the list of areas for a free spot 43 | '' 2. create a new area and insert it in the list 44 | '' 3. return the address of the area 45 | 46 | dim min_addr as uinteger = &h40000000 47 | dim insert_after as Listtype(address_space_area) ptr = @this.areas 48 | 49 | list_foreach(h, this.areas) 50 | dim x as address_space_area ptr = h->get_owner() 51 | 52 | insert_after = h 53 | 54 | '' Is the hole big enough? 55 | if (x->address > min_addr + pages) then 56 | list_foreach_exit 57 | end if 58 | 59 | '' try the next hole 60 | min_addr = cuint(x->address) + x->pages * PAGE_SIZE 61 | list_next(h) 62 | 63 | '' Did we walk through the list and didn't find a hole yet? 64 | if ((min_addr <> &h40000000) and (insert_after <> @this.areas)) then 65 | '' check if there's space at the end 66 | dim x as address_space_area ptr = this.areas.get_prev()->get_owner() 67 | if (x->address + x->pages*PAGE_SIZE < &hFFFFFFFF - pages) then 68 | min_addr = cuint(x->address) + x->pages*PAGE_SIZE 69 | insert_after = this.areas.get_prev() 70 | else 71 | '' Nope, nothing's free 72 | return 0 73 | end if 74 | end if 75 | 76 | '' Create new struct 77 | dim area as address_space_area ptr = new address_space_area(cast(any ptr, min_addr), pages, flags, description) 78 | 79 | '' insert it 80 | insert_after->insert_after(@area->list) 81 | 82 | '' return the area address 83 | return area 84 | end function 85 | 86 | sub address_space.insert_area (area as address_space_area ptr) 87 | assert(area->pages <> 0) 88 | dim insert_after as Listtype(address_space_area) ptr = @this.areas 89 | 90 | list_foreach(h, this.areas) 91 | dim x as address_space_area ptr = h->get_owner() 92 | 93 | if (x->address > area->address) then 94 | '' check for overlaps 95 | assert(area->address+area->pages*PAGE_SIZE <= x->address) 96 | 97 | list_foreach_exit 98 | else 99 | '' check for overlaps 100 | assert(x->address+x->pages*PAGE_SIZE <= area->address) 101 | end if 102 | 103 | insert_after = h 104 | list_next(h) 105 | 106 | insert_after->insert_after(@area->list) 107 | 108 | end sub 109 | -------------------------------------------------------------------------------- /kernel/src/modules.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "modules.bi" 20 | #include "multiboot.bi" 21 | #include "process.bi" 22 | #include "elf.bi" 23 | #include "kernel.bi" 24 | #include "panic.bi" 25 | #include "vmm.bi" 26 | #include "pmm.bi" 27 | #include "video.bi" 28 | 29 | declare sub load_module (multiboot_module as multiboot_module_t ptr, process as process_type ptr ptr) 30 | 31 | type module_list 32 | start as any ptr 33 | size as uinteger 34 | cmdline as any ptr 35 | end type 36 | 37 | 38 | 39 | 'dim shared init_process as process_type ptr 40 | 41 | sub load_init_module (mbinfo as multiboot_info ptr) 42 | '' if no modules are available, we have a problem 43 | if (mbinfo->mods_count = 0) then 44 | panic_error(!"No init-module available.\n") 45 | end if 46 | 47 | load_module(cast(multiboot_module_t ptr, mbinfo->mods_addr), @init_process) 48 | 49 | '' we loaded the module, so remove it from the list 50 | mbinfo->mods_addr += sizeof(multiboot_module_t) 51 | mbinfo->mods_count -= 1 52 | end sub 53 | 54 | sub load_modules (mbinfo as multiboot_info ptr) 55 | if (mbinfo->mods_count) = 0 then return 56 | 57 | dim mod_addr as multiboot_module_t ptr = cast(multiboot_module_t ptr, mbinfo->mods_addr) 58 | 59 | for index as uinteger = 0 to mbinfo->mods_count-1 60 | dim process as process_type ptr = nullptr 61 | load_module(mod_addr, @process) 62 | 63 | mod_addr += 1 64 | next 65 | end sub 66 | 67 | 68 | '' TODO: the cmdline should be given to the module somehow (e.g. do it like linux - /proc/pid/cmdline - we need vfs for this) 69 | sub load_module (multiboot_module as multiboot_module_t ptr, process as process_type ptr ptr) 70 | dim v_multiboot_module as multiboot_module_t ptr 71 | 72 | '' map the module structure 73 | v_multiboot_module = vmm_kernel_automap(multiboot_module, sizeof(multiboot_module_t)) 74 | if (v_multiboot_module = 0) then 75 | panic_error(!"Could not map the module-structure of the module\n") 76 | end if 77 | 78 | '' map the image 79 | dim size as uinteger = v_multiboot_module->mod_end - v_multiboot_module->mod_start 80 | dim v_image as uinteger = cuint(vmm_kernel_automap(cast(any ptr, v_multiboot_module->mod_start), size)) 81 | 82 | *process = new process_type() 83 | 84 | if (*process = nullptr) then 85 | panic_error(!"Could not create init-process!\n") 86 | end if 87 | 88 | dim thread as thread_type ptr 89 | 90 | if (not(elf_load_image(*process, @thread, v_image, size))) then 91 | panic_error(!"Could not load the init-module!") 92 | end if 93 | 94 | thread->activate() 95 | 96 | '' unmap the image, we don't need it any longer 97 | vmm_kernel_unmap(cast(any ptr, v_image), size) 98 | 99 | '' physically free the space occupied by the image 100 | for c as uinteger = 0 to num_pages(size)-1 101 | pmm_free(cast(any ptr, v_multiboot_module->mod_start + c*PAGE_SIZE)) 102 | next 103 | 104 | '' unmap the module struct 105 | vmm_kernel_unmap(v_multiboot_module, sizeof(multiboot_module_t)) 106 | end sub 107 | 108 | sub pass_modules_to_init (mbinfo as multiboot_info ptr) 109 | '' TODO: 110 | '' - map the multiboot-modules into init 111 | '' - create a list of modules in init 112 | '' - pass the address to init via the stack 113 | end sub 114 | -------------------------------------------------------------------------------- /kernel/src/elf.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2015 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "elf.bi" 20 | #include "elf32.bi" 21 | #include "process.bi" 22 | #include "thread.bi" 23 | #include "pmm.bi" 24 | #include "mem.bi" 25 | #include "panic.bi" 26 | 27 | function elf_header_check (header as Elf32_Ehdr ptr) as integer 28 | '' check for the magic value (&h7F, 'E', 'L', 'F') 29 | if ((header->e_ident.EI_MAGIC(0) <> &h7F) or _ 30 | (header->e_ident.EI_MAGIC(1) <> &h45) or _ 31 | (header->e_ident.EI_MAGIC(2) <> &h4C) or _ 32 | (header->e_ident.EI_MAGIC(3) <> &h46)) then return 1 33 | 34 | if (header->e_type <> ELF_ET_EXEC) then return 2 35 | if (header->e_machine <> ELF_EM_386) then return 3 36 | if (header->e_ident.EI_CLASS <> ELF_CLASS_32) then return 4 37 | if (header->e_ident.EI_DATA <> ELF_DATA_2LSB) then return 5 38 | if (header->e_version <> ELF_EV_CURRENT) then return 6 39 | return 0 40 | end function 41 | 42 | 43 | function elf_load_image (process as process_type ptr, thread as thread_type ptr ptr, image as uinteger, size as uinteger) as boolean 44 | dim header as Elf32_Ehdr ptr = cast(Elf32_Ehdr ptr, image) 45 | 46 | if (size < sizeof(Elf32_Ehdr)) then return false 47 | 48 | if (elf_header_check(header) > 0) then return false 49 | 50 | '' pointer to the first program header 51 | dim program_header as Elf32_Phdr ptr = cast(Elf32_Phdr ptr, cuint(header) + header->e_phoff) 52 | 53 | '' iterate over all segments 54 | for counter as uinteger = 0 to header->e_phnum-1 55 | '' skip segments that are not loadable 56 | if (program_header[counter].p_type <> ELF_PT_LOAD) then continue for 57 | 58 | '' align the start on page-boundaries 59 | dim start as uinteger = program_header[counter].p_vaddr and VMM_PAGE_MASK 60 | dim real_size as uinteger = program_header[counter].p_filesz + (program_header[counter].p_vaddr - start) 61 | dim real_mem_size as uinteger = program_header[counter].p_memsz + (program_header[counter].p_vaddr - start) 62 | 63 | '' start and end of the segment 64 | dim addr as uinteger = start 65 | dim end_addr as uinteger = start + real_size 66 | dim end_addr_mem as uinteger = start + real_mem_size 67 | 68 | dim area as address_space_area ptr = new address_space_area(cast(any ptr, start), num_pages(real_mem_size)) 69 | process->a_s.insert_area(area) 70 | 71 | 72 | while (addr < end_addr_mem) 73 | dim phys_mem as any ptr = pmm_alloc() 74 | dim mem as any ptr = vmm_kernel_automap(phys_mem, PAGE_SIZE) 75 | 76 | if (addr < end_addr) then 77 | dim remaining_copy as uinteger = end_addr - addr 78 | dim chunk_size as uinteger = iif(remaining_copy > PAGE_SIZE, PAGE_SIZE, remaining_copy) 79 | 80 | memcpy(mem,_ 81 | cast(any ptr, image + program_header[counter].p_offset + (addr-start)), _ 82 | chunk_size) 83 | 84 | if (PAGE_SIZE - chunk_size > 0) then memset(mem+chunk_size, 0, PAGE_SIZE-chunk_size) 85 | else 86 | memset(mem, 0, PAGE_SIZE) 87 | end if 88 | 89 | vmm_kernel_unmap(mem, PAGE_SIZE) 90 | 91 | vmm_map_page(@process->context, cast(any ptr, addr), cast(any ptr, phys_mem), VMM_PTE_FLAGS.WRITABLE or VMM_PTE_FLAGS.PRESENT or VMM_PTE_FLAGS.USERSPACE) 92 | 93 | addr += PAGE_SIZE 94 | wend 95 | next 96 | 97 | '' create the thread 98 | *thread = new thread_type(process, cast(any ptr, header->e_entry), 1) 99 | 100 | return true 101 | end function 102 | -------------------------------------------------------------------------------- /drivers/keyboard/src/main.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST 3 | ' Copyright (C) 2010-2018 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | '' PS/2 8042 keyboard controller driver 20 | 21 | #include "../../libfrost/frost.bi" 22 | #include "keyboard.bi" 23 | 24 | const KBC_COMMAND as ubyte = &h64 25 | const KBC_DATA as ubyte = &h60 26 | 27 | declare sub irq_handler (irq_number as uinteger) 28 | declare sub kbc_send_command (cmd as ubyte) 29 | 30 | sub outb (port as ushort, value as ubyte) 31 | asm 32 | movw dx, [port] 33 | movb al, [value] 34 | outb dx, al 35 | end asm 36 | end sub 37 | 38 | function inb (port as ushort) as ubyte 39 | asm 40 | movw dx, [port] 41 | inb al, dx 42 | mov [function], al 43 | end asm 44 | end function 45 | 46 | sub main () 47 | '' request access to the controller's ports 48 | frost_syscall_port_request(KBC_COMMAND) 49 | frost_syscall_port_request(KBC_DATA) 50 | 51 | frost_syscall_irq_handler_register(1, @irq_handler) 52 | 53 | '' clear the buffer 54 | while ((inb(KBC_COMMAND) and &h01) <> 0) 55 | inb(KBC_DATA) 56 | wend 57 | 58 | '' turn the LEDs off 59 | kbc_send_command(&hED) 60 | kbc_send_command(&h00) 61 | 62 | '' activate the keyboard 63 | kbc_send_command(&hF4) 64 | 65 | frost_syscall_43(strptr("Keyboard controller initialized")) 66 | 67 | asm jmp $ 68 | end sub 69 | 70 | sub irq_handler (irq_number as uinteger) 71 | while ((inb(KBC_COMMAND) and &h01) <> 0) 72 | if (irq_number = &h01) then 73 | dim is_break_code as integer = false 74 | dim keycode as ubyte 75 | static e0_code as integer = false 76 | static e1_code as integer = 0 77 | static e1_prev as ushort = 0 78 | dim scancode as ubyte = inb(KBC_DATA) 79 | 80 | if (bit(scancode, 7) and (e1_code or (scancode <> &hE1)) and (e0_code or (scancode <> &hE0))) then 81 | is_break_code = true 82 | scancode = bitreset(scancode, 7) 83 | end if 84 | 85 | if (e0_code) then 86 | '' catch fake-shift 87 | if ((scancode = &h2A) or (scancode = &h36)) then 88 | e0_code = false 89 | else 90 | keycode = scancode_to_keycode(1, scancode) 91 | e0_code = false 92 | end if 93 | elseif (e1_code = 2) then 94 | '' second (and last) byte of an e1-code 95 | e1_prev or= cushort(scancode) shl 8 96 | keycode = scancode_to_keycode(2, e1_prev) 97 | e1_code = 0 98 | elseif (e1_code = 1) then 99 | '' first byte of an e1-code 100 | e1_prev = scancode 101 | e1_code += 1 102 | elseif (scancode = &hE0) then 103 | '' beginning of an e0-code 104 | e0_code = true 105 | elseif (scancode = &hE1) then 106 | '' beginning of an e1-code 107 | e1_code = 1 108 | else 109 | '' normal scancode 110 | keycode = scancode_to_keycode(0, scancode) 111 | end if 112 | 113 | if (keycode <> 0) then 114 | if (is_break_code) then 115 | frost_syscall_43(strptr("Key released")) 116 | else 117 | frost_syscall_43(strptr("Key pressed")) 118 | end if 119 | end if 120 | end if 121 | wend 122 | 123 | frost_syscall_irq_handler_exit(irq_number) 124 | end sub 125 | 126 | sub kbc_send_command (cmd as ubyte) 127 | do 128 | '' wait until the input buffer is empty 129 | while ((inb(KBC_COMMAND) and &h02) <> 0) 130 | frost_syscall_thread_yield() 131 | wend 132 | 133 | outb(KBC_DATA, cmd) 134 | 135 | while ((inb(KBC_COMMAND) and &h01) = 0) 136 | frost_syscall_thread_yield() 137 | wend 138 | loop while (inb(KBC_DATA) = &hFE) 139 | end sub 140 | -------------------------------------------------------------------------------- /kernel/include/intrusive_list.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | #define Listtype(T_) Listtype_##T_ 22 | 23 | #macro DECLARE_LIST(T_) 24 | '' IMPORTANT: RefCountPtr needs to be declared BEFORE declaring the list! 25 | #if defined(RefCountPtr_##T_) 26 | '' this type seems to be refcounted! 27 | type Listtype_p_##T_ as RefCountPtr(T_) 28 | #define Listtype_r_##t_ 29 | #else 30 | '' not refcounted, use normal pointer 31 | type Listtype_p_##T_ as T_ ptr 32 | #endif 33 | 34 | 35 | type Listtype_t_##T_ as T_ 36 | 37 | type Listtype(T_) 38 | private: 39 | next_ptr as Listtype(T_) ptr 40 | prev_ptr as Listtype(T_) ptr 41 | owner as Listtype_p_##T_ 42 | public: 43 | declare constructor (offset as uinteger) 44 | declare constructor () 45 | declare destructor () 46 | declare sub insert_after (new_head as Listtype(T_) ptr) 47 | declare sub insert_before (new_head as Listtype(T_) ptr) 48 | declare sub remove () 49 | declare function is_empty () as integer 50 | declare function is_singular () as integer 51 | declare function get_next () as Listtype(T_) ptr 52 | declare function get_prev () as Listtype(T_) ptr 53 | declare function get_owner () as Listtype_p_##T_ 54 | end type 55 | #endmacro 56 | 57 | #macro DEFINE_LIST(T_) 58 | constructor Listtype(T_) (offset as uinteger) 59 | assert(offset <> 0) 60 | 61 | this.next_ptr = @this 62 | this.prev_ptr = @this 63 | #if defined(Listtype_r_##t_) 64 | this.owner = Listtype_p_##T_(cast(T_ ptr, cast(any ptr, @this)-offset)) 65 | #else 66 | this.owner = cast(Listtype_p_##T_, cast(any ptr, @this)-offset) 67 | #endif 68 | end constructor 69 | 70 | constructor Listtype(T_) () 71 | this.next_ptr = @this 72 | this.prev_ptr = @this 73 | #if not defined(Listtype_r_##t_) 74 | this.owner = 0 75 | #endif 76 | end constructor 77 | 78 | destructor Listtype(T_) 79 | this.remove() 80 | end destructor 81 | 82 | sub Listtype(T_).insert_after (new_head as Listtype(T_) ptr) 83 | new_head->next_ptr = this.next_ptr 84 | new_head->prev_ptr = @this 85 | 86 | this.next_ptr->prev_ptr = new_head 87 | this.next_ptr = new_head 88 | end sub 89 | 90 | sub Listtype(T_).insert_before (new_head as Listtype(T_) ptr) 91 | new_head->prev_ptr = this.prev_ptr 92 | new_head->next_ptr = @this 93 | 94 | this.prev_ptr->next_ptr = new_head 95 | this.prev_ptr = new_head 96 | end sub 97 | 98 | sub Listtype(T_).remove () 99 | this.prev_ptr->next_ptr = this.next_ptr 100 | this.next_ptr->prev_ptr = this.prev_ptr 101 | end sub 102 | 103 | function Listtype(T_).is_empty () as integer 104 | return (this.next_ptr = @this) 105 | end function 106 | 107 | function Listtype(T_).is_singular () as integer 108 | if (not this.is_empty()) then 109 | return (this.next_ptr = this.prev_ptr) 110 | end if 111 | 112 | return 0 113 | end function 114 | 115 | function Listtype(T_).get_next () as Listtype(T_) ptr 116 | return this.next_ptr 117 | end function 118 | 119 | function Listtype(T_).get_prev () as Listtype(T_) ptr 120 | return this.prev_ptr 121 | end function 122 | 123 | function Listtype(T_).get_owner () as Listtype_p_##T_ 124 | return this.owner 125 | end function 126 | #endmacro 127 | 128 | 129 | #macro list_foreach (ITERATOR_, LIST_) 130 | scope 131 | dim ITERATOR_ as typeof(LIST_) ptr = LIST_.get_next() 132 | while (ITERATOR_ <> @LIST_) 133 | 134 | #endmacro 135 | 136 | #define list_foreach_exit exit while 137 | 138 | #macro list_next (ITERATOR_) 139 | ITERATOR_ = ITERATOR_->get_next() 140 | wend 141 | end scope 142 | #endmacro 143 | -------------------------------------------------------------------------------- /kernel/src/lapic.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "apic.bi" 20 | #include "debug.bi" 21 | #include "cpu.bi" 22 | #include "vmm.bi" 23 | #include "pmm.bi" 24 | #include "pic.bi" 25 | #include "panic.bi" 26 | 27 | dim apic_enabled as boolean = false 28 | 29 | const LOCAL_APIC_BASE_MSR = &h1B 30 | const LOCAL_APIC_BASE_ADDR_MASK = &hFFFFFF000 31 | 32 | const LOCAL_APIC_REG_ID = &h0020 '' (RW) 33 | const LOCAL_APIC_REG_VERSION = &h0030 '' (R) 34 | const LOCAL_APIC_REG_TASK_PRIO = &h0080 '' (RW) 35 | const LOCAL_APIC_REG_ARBIT_PRIO = &h0090 '' (R) 36 | const LOCAL_APIC_REG_PROC_PRIO = &h00A0 '' (R) 37 | const LOCAL_APIC_REG_EOI = &h00B0 '' (W) 38 | const LOCAL_APIC_REG_REMOTE_READ = &h00C0 '' (R) 39 | const LOCAL_APIC_REG_LOGICAL_DEST = &h00D0 '' (RW) 40 | const LOCAL_APIC_REG_DEST_FORMAT = &h00E0 '' (RW) 41 | const LOCAL_APIC_REG_SPIV = &h00F0 '' (RW) 42 | const LOCAL_APIC_REG_ERROR_STATUS = &h0280 '' (R) 43 | const LOCAL_APIC_REG_LVT_CMCI = &h02F0 '' (RW) 44 | const LOCAL_APIC_REG_ICR_LOW = &h0300 '' (RW) 45 | const LOCAL_APIC_REG_ICR_HIGH = &h0310 '' (RW) 46 | const LOCAL_APIC_REG_LVT_TIMER = &h0320 '' (RW) 47 | const LOCAL_APIC_REG_LVT_THERM = &h0330 '' (RW) 48 | const LOCAL_APIC_REG_LVT_PERFMON = &h0340 '' (RW) 49 | const LOCAL_APIC_REG_LVT_LINT0 = &h0350 '' (RW) 50 | const LOCAL_APIC_REG_LVT_LINT1 = &h0360 '' (RW) 51 | const LOCAL_APIC_REG_LVT_ERROR = &h0370 '' (RW) 52 | const LOCAL_APIC_REG_TIMER_INITCNT = &h0380 '' (RW) 53 | const LOCAL_APIC_REG_TIMER_CURRCNT = &h0390 '' (R) 54 | const LOCAL_APIC_REG_TIMER_DIV = &h03E0 '' (RW) 55 | 56 | const LOCAL_APIC_SPIV_SOFT_ENABLE = &h100 57 | 58 | dim shared lapic_base_virt as uinteger = 0 59 | 60 | sub lapic_write_register (register_offset as uinteger, value as uinteger) 61 | *(cast(uinteger ptr, lapic_base_virt+register_offset)) = value 62 | end sub 63 | 64 | function lapic_read_register (register_offset as uinteger) as uinteger 65 | return *(cast(uinteger ptr, lapic_base_virt+register_offset)) 66 | end function 67 | 68 | '' TODO: set spurious interrupt vector 69 | '' FIXME: split up into "once"- and "per-cpu"-parts 70 | sub lapic_init () 71 | pic_mask_all() 72 | 73 | dim lapic_base_phys as uinteger = cuint(read_msr(LOCAL_APIC_BASE_MSR) and LOCAL_APIC_BASE_ADDR_MASK) 74 | write_msr(LOCAL_APIC_BASE_MSR, read_msr(LOCAL_APIC_BASE_MSR)) 75 | 76 | printk(LOG_DEBUG COLOR_GREEN "LAPIC: " COLOR_RESET !"base addr: %X\n", cuint(read_msr(LOCAL_APIC_BASE_MSR) and LOCAL_APIC_BASE_ADDR_MASK)) 77 | 78 | lapic_base_virt = cuint(vmm_kernel_automap(cast(any ptr, lapic_base_phys), PAGE_SIZE, VMM_FLAGS.KERNEL_DATA or VMM_PTE_FLAGS.NOT_CACHEABLE)) 79 | 80 | '' set the APIC Software Enable/Disable flag in the Spurious-Interrupt Vector Register 81 | '' FIXME: properly initialize the SPI vector. See manual 10.9, and http://forum.osdev.org/viewtopic.php?p=83547&sid=eb062848679db0c0532f4b97b949d104#p83547 82 | lapic_write_register(LOCAL_APIC_REG_SPIV, lapic_read_register(LOCAL_APIC_REG_SPIV) or LOCAL_APIC_SPIV_SOFT_ENABLE) 83 | 84 | apic_enabled = true 85 | end sub 86 | 87 | sub lapic_eoi () 88 | assert(apic_enabled = true) 89 | 90 | '' writing to the EOI register signals completion of the handler routine 91 | lapic_write_register(LOCAL_APIC_REG_EOI, 0) 92 | end sub 93 | 94 | '' FIXME: magic values are bad. 95 | '' FIXME: this currently always start the CPU with the local-APIC-ID 1, and 96 | '' the delay-loop is lousy. 97 | sub lapic_startup_ipi (trampoline_addr as any ptr) 98 | assert(apic_enabled = true) 99 | 100 | lapic_write_register(LOCAL_APIC_REG_ICR_HIGH, 1 shl 24) 101 | lapic_write_register(LOCAL_APIC_REG_ICR_LOW, (5 shl 8) or (1 shl 14)) 102 | 103 | for i as integer = 0 to &h0FFFFF 104 | 105 | next 106 | 107 | lapic_write_register(LOCAL_APIC_REG_ICR_HIGH, 1 shl 24) 108 | lapic_write_register(LOCAL_APIC_REG_ICR_LOW, (((cuint(trampoline_addr) \ &h1000) and &hFF) or (6 shl 8) or (1 shl 14))) 109 | end sub 110 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/gdt.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "kernel.bi" 20 | #include "gdt.bi" 21 | #include "video.bi" 22 | 23 | type gdtr_type field=1 24 | limit as ushort 25 | start as uinteger 26 | end type 27 | 28 | type gdt_type field=1 29 | limit_low as ushort 30 | start_low as ushort 31 | start_middle as ubyte 32 | accessbyte as ubyte 33 | flags_limit2 as ubyte 34 | start_high as ubyte 35 | end type 36 | 37 | '' flags for the access-byte 38 | const FLAG_PRESENT as ubyte = &h80 '' must be set for an active entry 39 | const FLAG_PRIVILEGE_RING_3 as ubyte = &h60 40 | const FLAG_PRIVILEGE_RING_2 as ubyte = &h40 41 | const FLAG_PRIVILEGE_RING_1 as ubyte = &h20 42 | const FLAG_PRIVILEGE_RING_0 as ubyte = &h00 43 | const FLAG_SEGMENT as ubyte = &h10 '' set for Code-/Data-segments, unset for gates and TSS 44 | const FLAG_EXECUTABLE as ubyte = &h08 '' unset = DS, set = CS 45 | const FLAG_DC as ubyte = &h04 46 | const FLAG_RW as ubyte = &h02 '' CS: read access, DS: write access 47 | const FLAG_ACCESSED as ubyte = &h01 '' set by CPU. DO NOT USE! 48 | const FLAG_TSS as ubyte = &h09 '' tss is a bit special 49 | 50 | '' flags for the flags-byte 51 | const FLAG_GRANULARITY as ubyte = &h08 '' if set, size is in 4KB units 52 | const FLAG_SIZE as ubyte = &h04 '' unset = 16 bit PM, set = 32 bit PM 53 | const FLAG_LONG_MODE as ubyte = &h02 '' if set, it's a long mode segment 54 | const FLAG_AVAILABLE as ubyte = &h01 '' free bit 55 | 56 | const TABLE_SIZE = 5 57 | 58 | declare sub gdt_set_entry (i as ushort, start as uinteger, limit as uinteger, access as ubyte, flags as ubyte) 59 | 60 | dim shared gdtr as gdtr_type 61 | dim shared gdt (0 to TABLE_SIZE) as gdt_type 62 | dim shared tss as task_state_segment 63 | 64 | 65 | '' this sub initializes the GDT with Code- and Data-Segments for Ring 0 and Ring 3. 66 | '' it also does basic tss-setup 67 | sub gdt_prepare () 68 | tss_ptr = @tss '' initialize the tss-pointer (used in other parts of the kernel) 69 | tss.ss0 = &h10 '' set the kernel stack segment of the tss 70 | tss.io_bitmap_offset = TSS_IO_BITMAP_NOT_LOADED 71 | 72 | '' RING-0 Code-Segment 73 | gdt_set_entry(1, 0, &hFFFFF, (FLAG_PRESENT or FLAG_PRIVILEGE_RING_0 or FLAG_SEGMENT or FLAG_EXECUTABLE or FLAG_RW), (FLAG_GRANULARITY or FLAG_SIZE)) 74 | 75 | '' RING-0 Data-Segment 76 | gdt_set_entry(2, 0, &hFFFFF, (FLAG_PRESENT or FLAG_PRIVILEGE_RING_0 or FLAG_SEGMENT or FLAG_RW), (FLAG_GRANULARITY or FLAG_SIZE)) 77 | 78 | '' RING-3 Code-Segment 79 | gdt_set_entry(3, 0, &hFFFFF, (FLAG_PRESENT or FLAG_PRIVILEGE_RING_3 or FLAG_SEGMENT or FLAG_EXECUTABLE or FLAG_RW), (FLAG_GRANULARITY or FLAG_SIZE)) 80 | 81 | '' RING-3 Data-Segment 82 | gdt_set_entry(4, 0, &hFFFFF, (FLAG_PRESENT or FLAG_PRIVILEGE_RING_3 or FLAG_SEGMENT or FLAG_RW), (FLAG_GRANULARITY or FLAG_SIZE)) 83 | 84 | '' TSS 85 | gdt_set_entry(5, cuint(tss_ptr), sizeof(task_state_segment), (FLAG_PRESENT or FLAG_PRIVILEGE_RING_3 or FLAG_TSS), 0) 86 | 87 | gdtr.limit = (TABLE_SIZE+1)*8-1 '' calculate the size of the entries + null-entry 88 | gdtr.start = cuint(@gdt(0)) '' set the address of the table 89 | end sub 90 | 91 | sub gdt_load () 92 | '' load the gdt 93 | asm lgdt [gdtr] 94 | 95 | '' refresh the segment registers, so the gdt is really being used 96 | asm 97 | mov ax, &h10 98 | mov ds, ax 99 | mov es, ax 100 | mov fs, ax 101 | mov gs, ax 102 | mov ss, ax 103 | ljmp &h08:gdt_jmp 104 | gdt_jmp: 105 | end asm 106 | 107 | '' load the task-register 108 | asm 109 | mov ax, &h28 110 | ltr ax 111 | end asm 112 | end sub 113 | 114 | '' this sub is just a helper function to provide easier access to the GDT. 115 | '' it puts the passed arguments in the right place of a GDT-entry. 116 | sub gdt_set_entry (index as ushort, start as uinteger, limit as uinteger, accessbyte as ubyte, flags as ubyte) 117 | gdt(index).limit_low = loword(limit) 118 | gdt(index).start_low = loword(start) 119 | gdt(index).start_middle = lobyte(hiword(start)) 120 | gdt(index).accessbyte = accessbyte 121 | gdt(index).flags_limit2 = (lobyte(hiword(limit)) and &h0F) 122 | gdt(index).flags_limit2 or= ((flags shl 4) and &hF0) 123 | gdt(index).start_high = hibyte(hiword(start)) 124 | end sub 125 | -------------------------------------------------------------------------------- /kernel/src/interrupt_handler.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2016 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "kernel.bi" 20 | #include "interrupt_handler.bi" 21 | #include "isf.bi" 22 | #include "thread.bi" 23 | #include "interrupt.bi" 24 | #include "apic.bi" 25 | #include "process.bi" 26 | #include "syscall.bi" 27 | #include "panic.bi" 28 | #include "pmm.bi" 29 | #include "kmm.bi" 30 | 31 | DECLARE_LIST(irq_handler_type) 32 | DEFINE_LIST(irq_handler_type) 33 | 34 | type irq_handler_type 35 | process as process_type ptr 36 | handler as any ptr 37 | 38 | list as Listtype(irq_handler_type) = Listtype(irq_handler_type)(offsetof(irq_handler_type, list)) 39 | 40 | declare operator new (size as uinteger) as any ptr 41 | declare operator new[] (size as uinteger) as any ptr 42 | declare operator delete (buffer as any ptr) 43 | 44 | declare constructor (process as process_type ptr, handler as any ptr) 45 | end type 46 | 47 | operator irq_handler_type.new (size as uinteger) as any ptr 48 | return kmalloc(size) 49 | '' constructor is called automatically 50 | end operator 51 | 52 | operator irq_handler_type.delete (buffer as any ptr) 53 | kfree(buffer) 54 | '' destructor is called automatically 55 | end operator 56 | 57 | constructor irq_handler_type (process as process_type ptr, handler as any ptr) 58 | this.process = process 59 | this.handler = handler 60 | end constructor 61 | 62 | dim shared irq_handlers(0 to 15) as Listtype(irq_handler_type) 63 | 64 | function register_irq_handler (process as process_type ptr, irq as integer, handler_address as any ptr) as boolean 65 | if ((irq < lbound(irq_handlers,1)) or (irq > ubound(irq_handlers,1))) then return false 66 | 67 | dim h as irq_handler_type ptr = new irq_handler_type(process, handler_address) 68 | irq_handlers(irq).insert_after(@h->list) 69 | 70 | '' FIXME: hardcoding the x86 IRQ-offset? naaaaaaah.... 71 | interrupt_unmask(irq+&h20) 72 | return true 73 | end function 74 | 75 | '' this is the common interrupt handler which gets called for every interrupt. 76 | function handle_interrupt cdecl (isf as interrupt_stack_frame ptr) as interrupt_stack_frame ptr 77 | dim reschedule as uinteger = false 78 | 79 | select case isf->int_nr 80 | case 0 to &h0C '' exception 81 | panic_exception(isf) '' show panic screen 82 | 83 | case &h0D 84 | if (tss_ptr->io_bitmap_offset = TSS_IO_BITMAP_NOT_LOADED) then 85 | set_io_bitmap() 86 | else 87 | panic_exception(isf) 88 | end if 89 | 90 | case &h0E to &h13 91 | panic_exception(isf) 92 | 93 | case &h21 to &h2F 94 | '' spurious IRQ? 95 | if (interrupt_is_spurious(isf->int_nr)) then 96 | '' takes care of spurious interrupts and sends EOI if needed 97 | interrupt_eoi(isf->int_nr) 98 | return isf 99 | end if 100 | 101 | '' mask the IRQ to prevent it from firing again (gets unmasked when the thread is done) 102 | '' even when no popup-thread was created we mask to prevent IRQ-storms 103 | interrupt_mask(isf->int_nr) 104 | 105 | '' IRQ 106 | list_foreach(h, irq_handlers(isf->int_nr-&h20)) 107 | dim x as irq_handler_type ptr = h->get_owner() 108 | dim thread as thread_type ptr = new thread_type(x->process, x->handler, 1, THREAD_FLAG_POPUP) 109 | 110 | dim stack_p as any ptr = vmm_resolve(@(thread->parent_process->context), thread->stack_area->address + (thread->stack_area->pages-1)*PAGE_SIZE) 111 | dim m as uinteger ptr = vmm_kernel_automap(cast(any ptr, stack_p), PAGE_SIZE) 112 | m[PAGE_SIZE\4-1] = isf->int_nr-&h20 113 | m[PAGE_SIZE\4-2] = 0 '' return address, needed because of cdecl! 114 | vmm_kernel_unmap(m, PAGE_SIZE) 115 | thread->isf->esp -= 8 116 | 117 | thread->activate() 118 | list_next(h) 119 | 120 | case &h20 '' timer IRQ 121 | reschedule = true 122 | 123 | case &hFF '' syscall interrupt 124 | isf->eax = syscall_handler(isf->eax, isf->ebx, isf->esi, isf->edi) 125 | 126 | case else 127 | 128 | end select 129 | 130 | if (get_current_thread() <> nullptr) then 131 | if (get_current_thread()->flags and THREAD_FLAG_RESCHEDULE) then 132 | reschedule = true 133 | get_current_thread()->flags and= not THREAD_FLAG_RESCHEDULE 134 | end if 135 | end if 136 | 137 | if (reschedule) then 138 | thread_switch(isf) 139 | end if 140 | 141 | '' important: send EOI if necessary 142 | interrupt_eoi(isf->int_nr) 143 | 144 | return get_current_thread()->isf 145 | end function 146 | -------------------------------------------------------------------------------- /kernel/src/panic.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "panic.bi" 20 | #include "isf.bi" 21 | #include "video.bi" 22 | 23 | sub panic_set_clear_on_panic (b as boolean) 24 | panic_clear_on_panic = b 25 | end sub 26 | 27 | sub panic_hlt () 28 | printk(LOG_ERR COLOR_RED !"\nSYSTEM HALTED") 29 | cpu_halt() 30 | end sub 31 | 32 | sub panic_exception (isf as interrupt_stack_frame ptr) 33 | cpu_disable_interrupts() 34 | if (panic_clear_on_panic) then video_clean() 35 | printk(LOG_ERR COLOR_RED !"\n--------------------------------------------------------------------------------") 36 | printk(LOG_ERR !"\nKERNEL PANIC\n") 37 | 38 | select case (isf->int_nr) 39 | case &h00 40 | printk(LOG_ERR !"EXCEPTION 0x00 - Division by Zero (#DE)\n") 41 | case &h01 42 | printk(LOG_ERR !"EXCEPTION 0x01 - Debug (#DB)\n") 43 | case &h02 44 | printk(LOG_ERR !"EXCEPTION 0x02 - Non-maskable Interrupt (#NMI)\n") 45 | case &h03 46 | printk(LOG_ERR !"EXCEPTION 0x03 - Breakpoint (#BP)\n") 47 | case &h04 48 | printk(LOG_ERR !"EXCEPTION 0x04 - Overflow (#OF)\n") 49 | case &h05 50 | printk(LOG_ERR !"EXCEPTION 0x05 - Bound Range Exceeded (#BR)\n") 51 | case &h06 52 | printk(LOG_ERR !"EXCEPTION 0x06 - Invalid Opcode (#UD)\n") 53 | case &h07 54 | printk(LOG_ERR !"EXCEPTION 0x07 - Device Not Available (#NM)\n") 55 | case &h08 56 | printk(LOG_ERR !"EXCEPTION 0x08 - Double Fault (#DF)\n") 57 | case &h09 58 | printk(LOG_ERR !"EXCEPTION 0x09 - Coprocessor Segment Overrun\n") 59 | case &h0A 60 | printk(LOG_ERR !"EXCEPTION 0x0A - Invalid TSS (#TS)\n") 61 | case &h0B 62 | printk(LOG_ERR !"EXCEPTION 0x0B - Segment Not Present (#NP)\n") 63 | case &h0C 64 | printk(LOG_ERR !"EXCEPTION 0x0C - Stack-Segment Fault (#SS)\n") 65 | case &h0D 66 | printk(LOG_ERR !"EXCEPTION 0x0D - General Protection Fault (#GP)\n") 67 | case &h0E 68 | printk(LOG_ERR !"EXCEPTION 0x0E - Page Fault (#PF)\n") 69 | printk(LOG_ERR COLOR_RED !" - page active : ") 70 | if (isf->errorcode and &h01) then 71 | printk(LOG_ERR COLOR_RESET !"yes\n") 72 | else 73 | printk(LOG_ERR COLOR_RESET !"no\n") 74 | end if 75 | printk(LOG_ERR COLOR_RED !" - access type : ") 76 | if (isf->errorcode and &h02) then 77 | printk(LOG_ERR COLOR_RESET !"write\n") 78 | else 79 | printk(LOG_ERR COLOR_RESET !"read\n") 80 | end if 81 | printk(LOG_ERR COLOR_RED !" - rights : ") 82 | if (isf->errorcode and &h04) then 83 | printk(LOG_ERR COLOR_RESET !"user\n") 84 | else 85 | printk(LOG_ERR COLOR_RESET !"kernel\n") 86 | end if 87 | printk(LOG_ERR COLOR_RED !" - reserved : ") 88 | if (isf->errorcode and &h08) then 89 | printk(LOG_ERR COLOR_RESET !"yes\n") 90 | else 91 | printk(LOG_ERR COLOR_RESET !"no\n") 92 | end if 93 | printk(LOG_ERR COLOR_RED !" - access target: ") 94 | if (isf->errorcode and &h10) then 95 | printk(LOG_ERR COLOR_RESET !"code\n") 96 | else 97 | printk(LOG_ERR COLOR_RESET !"data\n") 98 | end if 99 | case &h0F 100 | printk(LOG_ERR !"EXCEPTION 0x0F - RESERVED\n") 101 | case &h10 102 | printk(LOG_ERR !"EXCEPTION 0x10 - x87 Floating Point (#MF)\n") 103 | case &h11 104 | printk(LOG_ERR !"EXCEPTION 0x11 - Alignment Check (#AC)\n") 105 | case &h12 106 | printk(LOG_ERR !"EXCEPTION 0x12 - Machine Check (#MC)\n") 107 | case &h13 108 | printk(LOG_ERR !"EXCEPTION 0x13 - SIMD Floating Point (#XM/#XF)\n") 109 | case &h14 to &h1F 110 | printk(LOG_ERR !"EXCEPTION - RESERVED EXCEPTION\n") 111 | end select 112 | 113 | printk(LOG_ERR !"\n") 114 | printk(LOG_ERR COLOR_RED "error: " COLOR_RESET !"0x%08X\n", isf->errorcode) 115 | 116 | dim as uinteger t_cr0, t_cr2, t_cr3 117 | 118 | asm 119 | mov eax, cr0 120 | mov [t_cr0], eax 121 | mov eax, cr2 122 | mov [t_cr2], eax 123 | mov eax, cr3 124 | mov [t_cr3], eax 125 | end asm 126 | printk(LOG_ERR COLOR_RED "cr0: " COLOR_RESET "0x%08X" COLOR_RED ", cr2: " COLOR_RESET "0x%08X" COLOR_RED ", cr3: " COLOR_RESET !"0x%08X\n", t_cr0, t_cr2, t_cr3) 127 | printk(LOG_ERR COLOR_RED "eax: " COLOR_RESET "0x%08X" COLOR_RED ", ebx: " COLOR_RESET "0x%08X" COLOR_RED ", ecx: " COLOR_RESET "0x%08X" COLOR_RED ", edx: " COLOR_RESET !"0x%08X\n", isf->eax, isf->ebx, isf->ecx, isf->edx) 128 | printk(LOG_ERR COLOR_RED "ebp: " COLOR_RESET "0x%08X" COLOR_RED ", esp: " COLOR_RESET "0x%08X" COLOR_RED ", esi: " COLOR_RESET "0x%08X" COLOR_RED ", edi: " COLOR_RESET !"0x%08X\n", isf->ebp, isf->esp, isf->esi, isf->edi) 129 | printk(LOG_ERR COLOR_RED "eip: " COLOR_RESET "0x%08X" COLOR_RED ", ss: " COLOR_RESET "0x%04X" COLOR_RED ", cs: " COLOR_RESET "0x%04X" COLOR_RED ", eflags: " COLOR_RESET !"0x%08X\n", isf->eip, isf->ss, isf->cs, isf->eflags) 130 | 131 | ' maybe print some other registers here 132 | panic_hlt() 133 | end sub 134 | -------------------------------------------------------------------------------- /kernel/src/vfs.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "vfs.bi" 20 | #include "kernel.bi" 21 | #include "string_tokenizer.bi" 22 | #include "zstring.bi" 23 | #include "video.bi" 24 | #include "process.bi" 25 | 26 | DEFINE_LIST(vfs_node) 27 | DEFINE_REFCOUNTPTR(vfs_node) 28 | 29 | dim shared vfs_root as RefCountPtr(vfs_node) 30 | dim shared fd_id_generator as uid128_generator 31 | 32 | sub vfs_init () 33 | vfs_root = new vfs_node("vfs_root", nullptr, VFS_FLAGS_KERNEL_NODE) 34 | 35 | var one = new vfs_node("vfs_1", vfs_root.ref, VFS_FLAGS_KERNEL_NODE) 36 | var two = new vfs_node("vfs_2", vfs_root.ref, VFS_FLAGS_KERNEL_NODE) 37 | var three = new vfs_node("vfs_3", vfs_root.ref, VFS_FLAGS_KERNEL_NODE) 38 | 39 | var testnode = new vfs_node("testnode", two, VFS_FLAGS_KERNEL_NODE) 40 | 41 | var t = vfs_parse_path("/vfs_2/testnode") 42 | printk(LOG_DEBUG !"node name: %s\n", t->name) 43 | end sub 44 | 45 | function vfs_get_root as RefCountPtr(vfs_node) 46 | return vfs_root 47 | end function 48 | 49 | operator vfs_node.new (size as uinteger) as any ptr 50 | return kmalloc(size) 51 | end operator 52 | 53 | operator vfs_node.delete (buffer as any ptr) 54 | kfree(buffer) 55 | end operator 56 | 57 | constructor vfs_node (name as zstring ptr, parent as vfs_node ptr, flags as integer, owner as process_type ptr = nullptr) 58 | '' TODO: don't rely on userspace string pointers, copy instead 59 | this.name = name 60 | this.parent = parent 61 | this.flags = flags 62 | this.owner = owner 63 | 64 | if (parent <> nullptr) then 65 | '' TODO: maybe keep the list sorted somehow? 66 | parent->child_list.insert_after(@this.node_list) 67 | end if 68 | end constructor 69 | 70 | function vfs_node.getChildByName (name as zstring) as RefCountPtr(vfs_node) 71 | '' loop through all child nodes, search for the one with the right name 72 | list_foreach(child, this.child_list) 73 | dim child_node as RefCountPtr(vfs_node) = child->get_owner() 74 | 75 | if (zstring_cmp(name, *child_node->name) = 0) then 76 | return child_node 77 | end if 78 | list_next(child) 79 | 80 | return nullptr 81 | end function 82 | 83 | DEFINE_LIST(vfs_fd) 84 | 85 | operator vfs_fd.new (size as uinteger) as any ptr 86 | return kmalloc(size) 87 | end operator 88 | 89 | operator vfs_fd.delete (buffer as any ptr) 90 | kfree(buffer) 91 | end operator 92 | 93 | constructor vfs_fd (process as process_type ptr, node as RefCountPtr(vfs_node)) 94 | this.id = fd_id_generator.generate() 95 | this.node = node 96 | 97 | '' add ourself to a list of descriptors for this process 98 | process->file_descriptors.insert_after(@this.fd_list) 99 | end constructor 100 | 101 | function vfs_parse_path (path as zstring) as RefCountPtr(vfs_node) 102 | if (path[0] = asc("/")) then 103 | dim cur_node as RefCountPtr(vfs_node) = vfs_root 104 | dim st as StringTokenizer = StringTokenizer(@path) 105 | do 106 | dim x as zstring ptr = st.getToken(strptr("/")) 107 | if (x = 0) then exit do 108 | 109 | cur_node = cur_node->getChildByName(*x) 110 | 111 | if (cur_node.ref = nullptr) then exit do 112 | loop 113 | 114 | return cur_node 115 | end if 116 | 117 | return RefCountPtr(vfs_node) 118 | end function 119 | 120 | function vfs_parse_path_afap (path as zstring) as RefCountPtr(vfs_node) 121 | if (path[0] = asc("/")) then 122 | dim cur_node as RefCountPtr(vfs_node) = vfs_root 123 | dim st as StringTokenizer = StringTokenizer(@path) 124 | do 125 | dim x as zstring ptr = st.getToken(strptr("/")) 126 | if (x = 0) then exit do 127 | 128 | dim next_node as RefCountPtr(vfs_node) = cur_node->getChildByName(*x) 129 | if (next_node.ref = nullptr) then exit do 130 | cur_node = next_node 131 | loop 132 | 133 | return cur_node 134 | end if 135 | 136 | return RefCountPtr(vfs_node) 137 | end function 138 | 139 | function vfs_create (path as zstring ptr, name_ as zstring ptr, owner as process_type ptr) as RefCountPtr(vfs_node) 140 | '' the path must be cached in the VFS - we don't support arbitrary paths at the moment (should we ever?) 141 | 142 | '' parse the path to get the parent-node 143 | dim parent_node as RefCountPtr(vfs_node) = vfs_parse_path(*path) 144 | if (parent_node.get_count() = 0) then return nullptr 145 | 146 | '' create, register & return the new node 147 | dim new_node as RefCountPtr(vfs_node) = new vfs_node(name_, parent_node.ref, 0, owner) 148 | return new_node 149 | end function 150 | 151 | function vfs_open (thread as thread_type ptr, path as zstring ptr, flags as uinteger) as vfs_fd ptr 152 | '' TODO: what about permissions? 153 | '' TODO: error-signaling is very unprecise 154 | 155 | '' parse the path and get the node 156 | dim node as RefCountPtr(vfs_node) = vfs_parse_path(*path) 157 | if (node.get_count() = 0) then return nullptr 158 | 159 | '' create a new file-descriptor 160 | dim fd as vfs_fd ptr = new vfs_fd(thread->parent_process, node) 161 | return fd 162 | end function 163 | -------------------------------------------------------------------------------- /kernel/src/main.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "multiboot.bi" 20 | #include "gdt.bi" 21 | #include "idt.bi" 22 | #include "acpi.bi" 23 | #include "apic.bi" 24 | #include "interrupt.bi" 25 | #include "pit.bi" 26 | #include "pmm.bi" 27 | #include "vmm.bi" 28 | #include "kmm.bi" 29 | #include "mem.bi" 30 | #include "process.bi" 31 | #include "modules.bi" 32 | #include "debug.bi" 33 | #include "panic.bi" 34 | #include "video.bi" 35 | #include "zstring.bi" 36 | #include "cpu.bi" 37 | #include "smp.bi" 38 | #include "io_man.bi" 39 | #include "vfs.bi" 40 | 41 | sub parse_cmdline (cmd_string as zstring ptr) 42 | if (zstring_instr(*cmd_string, "-verbose") > 0) then 43 | debug_set_loglevel(0) '' show every log-message 44 | else 45 | debug_set_loglevel(2) '' show only critical messages 46 | end if 47 | 48 | if (zstring_instr(*cmd_string, "-no-clear-on-panic") > 0) then 49 | panic_set_clear_on_panic(false) 50 | else 51 | panic_set_clear_on_panic(true) 52 | end if 53 | 54 | #if defined (FROST_DEBUG) 55 | if (zstring_instr(*cmd_string, "-serial-debugging") > 0) then 56 | debug_serial_init() 57 | 58 | if (zstring_instr(*cmd_string, "-serial-colorized") > 0) then 59 | video_serial_set_colorized(true) 60 | end if 61 | end if 62 | #endif 63 | end sub 64 | 65 | '' TODO: move this to some better place 66 | declare sub sysenter_entry () 67 | 68 | '' this sub really is the main function of the kernel. 69 | '' it is called by start.asm after setting up the stack. 70 | sub main (magicnumber as multiboot_uint32_t, t_mbinfo as multiboot_info ptr) 71 | '' we copy the mbinfo structure so it gets automatically mapped with the kernel 72 | dim mb_info as multiboot_info 73 | memcpy(@mb_info, t_mbinfo, sizeof(multiboot_info)) 74 | 75 | video_clean() 76 | video_hide_cursor() 77 | 78 | if (mb_info.flags and MULTIBOOT_INFO_CMDLINE) then 79 | parse_cmdline(cast(zstring ptr, mb_info.cmdline)) 80 | end if 81 | 82 | printk(LOG_INFO COLOR_BLUE !"FROST (%s)\n" COLOR_RESET, FROST_VERSION) 83 | printk(LOG_INFO COLOR_GREEN "bootloader: " COLOR_RESET !"%s\n", cast(zstring ptr, mb_info.boot_loader_name)) 84 | printk(LOG_INFO COLOR_GREEN "cmdline: " COLOR_RESET !"%s\n", cast(zstring ptr, mb_info.cmdline)) 85 | 86 | scope 87 | dim zstr as zstring*13 88 | cpu_get_vendor(@zstr) 89 | printk(LOG_INFO !"CPU vendor: %s\n", @zstr) 90 | end scope 91 | 92 | gdt_prepare() 93 | gdt_load() 94 | idt_prepare() 95 | idt_load() 96 | 97 | pit_set_frequency(100) 98 | 99 | acpi_init() 100 | 101 | '' two-step initialization of the PMM 102 | '' (the normal-allocator needs paging) 103 | pmm_init(@mb_info, PMM_ZONE_DMA24) 104 | printk(LOG_INFO COLOR_GREEN "PMM: " COLOR_RESET !"DMA24 zone initialized\n") 105 | vmm_init() 106 | pmm_init(@mb_info, PMM_ZONE_NORMAL) 107 | printk(LOG_INFO COLOR_GREEN "PMM: " COLOR_RESET !"normal zone initialized\n") 108 | printk(LOG_INFO COLOR_GREEN "PMM: " COLOR_RESET !"total RAM: %uMiB, free RAM: %uMiB\n", cuint(pmm_get_total()\1048576), cuint(pmm_get_free()\1048576)) 109 | vmm_init_local() 110 | printk(LOG_INFO COLOR_GREEN "VMM: " COLOR_RESET !"paging initialized\n") 111 | 112 | interrupt_init() 113 | 114 | printk(LOG_INFO COLOR_GREEN "KMM: " COLOR_RESET !"initializing heap\n") 115 | 116 | '' initialize the heap: 117 | '' starts at 256MB 118 | '' initial size 1MB 119 | '' minimum size 1MB 120 | '' maximum size 256MB 121 | kmm_init(&h10000000, &h10100000, &h100000, &h10000000) 122 | printk(LOG_INFO COLOR_GREEN "KMM: " COLOR_RESET !"heap initialized\n") 123 | 124 | if (cpu_has_local_apic()) then 125 | printk(LOG_INFO COLOR_GREEN "LAPIC: " COLOR_RESET !"CPU has local APIC\n") 126 | 'lapic_init() 127 | '' ioapic_init() 128 | end if 129 | 130 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"initializing\n") 131 | 'smp_init() 132 | 133 | printk(LOG_INFO COLOR_GREEN "VFS: " COLOR_RESET !"initializing...\n") 134 | vfs_init() 135 | 136 | init_ports() 137 | 138 | printk(LOG_INFO !"loading init module...") 139 | load_init_module(@mb_info) 140 | printk(LOG_INFO !"done.\n") 141 | 142 | printk(LOG_INFO !"loading modules...") 143 | load_modules(@mb_info) 144 | printk(LOG_INFO !"done.\n") 145 | 146 | '' TODO: We should only set up SYSENTER if the CPU supports it 147 | write_msr(MSR_IA32_SYSENTER_CS, &h0008) 148 | write_msr(MSR_IA32_SYSENTER_EIP, cuint(@sysenter_entry)) 149 | 150 | thread_create_idle_thread() 151 | interrupt_unmask(&h20) 152 | 153 | '' the scheduler takes over here 154 | asm sti 155 | do : loop 156 | end sub 157 | 158 | extern start_ctors alias "start_ctors" as byte 159 | extern end_ctors alias "end_ctors" as byte 160 | extern start_dtors alias "start_dtors" as byte 161 | extern end_dtors alias "end_dtors" as byte 162 | 163 | sub kinit () 164 | dim ctor as uinteger ptr = cast(uinteger ptr, @start_ctors) 165 | 166 | while ctor < @end_ctors 167 | dim ictor as sub () = cast(sub(), *ctor) 168 | ictor() 169 | 170 | ctor += 1 171 | wend 172 | end sub 173 | -------------------------------------------------------------------------------- /kernel/src/pmm.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "pmm.bi" 20 | #include "vmm.bi" 21 | #include "mem.bi" 22 | #include "kernel.bi" 23 | #include "multiboot.bi" 24 | #include "spinlock.bi" 25 | #include "panic.bi" 26 | 27 | '' the amount of free memory 28 | dim shared free_mem as uinteger = 0 29 | dim shared total_mem as uinteger = 0 30 | 31 | function pmm_get_total () as uinteger 32 | return total_mem 33 | end function 34 | 35 | function pmm_get_free () as uinteger 36 | return free_mem 37 | end function 38 | 39 | function pmm_intersect (page_addr as addr_t, area_start as addr_t, area_end as addr_t) as boolean 40 | if ((area_start >= page_addr) and (area_start <= page_addr+PAGE_SIZE)) then return true 41 | if ((area_end >= page_addr) and (area_end <= page_addr+PAGE_SIZE)) then return true 42 | if ((area_start <= page_addr) and (area_end >= page_addr+PAGE_SIZE)) then return true 43 | 44 | return false 45 | end function 46 | 47 | sub pmm_init (mbinfo as multiboot_info ptr, zone as uinteger) 48 | '' 1. all memory is used by default 49 | '' 2. all free areas are put on the stack, but checked against reserved areas 50 | '' 3. reserved are: 51 | '' - memory used by the kernel code 52 | '' - video memory 53 | '' - modules and their cmdlines 54 | '' done 55 | 56 | '' initialization is slow, usage is fast (with a bitmap it's exactly the opposite) 57 | '' 1. mark the whole memory as used 58 | '' 2. free the memory marked as free in the memory-map 59 | '' 3. mark the whole memory used by the kernel as used 60 | '' 4. mark the video memory as used 61 | '' 5. mark the modules and their cmdline as used 62 | 63 | if ((mbinfo->flags and MULTIBOOT_INFO_MEM_MAP) = 0) then 64 | panic_error(!"Memory map not available!\n") 65 | end if 66 | 67 | assert((vmm_is_paging_ready() and cbool(zone = PMM_ZONE_NORMAL)) or ((not vmm_is_paging_ready()) and cbool(zone = PMM_ZONE_DMA24))) 68 | 69 | if (zone = PMM_ZONE_DMA24) then pmm_init_dma24() 70 | 71 | dim mmap as multiboot_mmap_entry ptr = cast(multiboot_mmap_entry ptr, mbinfo->mmap_addr) 72 | dim mmap_end as multiboot_mmap_entry ptr = cast(multiboot_mmap_entry ptr, (mbinfo->mmap_addr + mbinfo->mmap_length)) 73 | 74 | '' free the memory listed in the memory-map 75 | while (mmap < mmap_end) 76 | '' only free regions that are marked as available 77 | if (mmap->type = MULTIBOOT_MEMORY_AVAILABLE) then 78 | '' don't free memory over 4GB, needs to be fixed to properly work on 64bit 79 | if (cuint((mmap->addr shr 32) and &hFFFFFFFF) = 0) then 80 | '' free each block of the region 81 | for addr as addr_t = mmap->addr to (mmap->addr+mmap->len-1) step PAGE_SIZE 82 | if (zone = PMM_ZONE_DMA24) and (addr >= 16*1024*1024) then exit for 83 | 84 | if (zone = PMM_ZONE_NORMAL) and (addr < 16*1024*1024) then continue for 85 | 86 | total_mem += PAGE_SIZE 87 | 88 | '' check if the block contains used memory 89 | '' does the block contain kernel memory? 90 | if (pmm_intersect(addr, caddr(kernel_start), caddr(kernel_end))) then continue for 91 | 92 | if (pmm_intersect(addr, mbinfo->cmdline, mbinfo->cmdline+PAGE_SIZE)) then continue for 93 | 94 | '' does the block contain video memory? 95 | if (pmm_intersect(addr, &hB8000, &hB8000+PAGE_SIZE)) then continue for 96 | 97 | '' iterate over the module list 98 | dim module_ptr as multiboot_mod_list ptr = cast(any ptr, mbinfo->mods_addr) 99 | 100 | for counter as uinteger = 1 to mbinfo->mods_count 101 | if (pmm_intersect(addr, module_ptr[counter-1].mod_start, module_ptr[counter-1].mod_end)) then 102 | continue for, for 103 | end if 104 | 105 | if (pmm_intersect(addr, module_ptr[counter-1].cmdline, module_ptr[counter-1].cmdline+PAGE_SIZE)) then 106 | continue for, for 107 | end if 108 | next 109 | 110 | '' &h1000 is reserved for the SMP trampoline-code 111 | if (addr = &h1000) then continue for 112 | 113 | '' free one block at a time 114 | if (zone = PMM_ZONE_NORMAL) then 115 | pmm_free_normal(cast(any ptr, cuint(addr))) 116 | free_mem += PAGE_SIZE 117 | elseif (zone = PMM_ZONE_DMA24) then 118 | pmm_free_dma24(cast(any ptr, cuint(addr))) 119 | free_mem += PAGE_SIZE 120 | end if 121 | next 122 | end if 123 | end if 124 | '' go to the next entry of the map 125 | mmap = cast(multiboot_mmap_entry ptr, cuint(mmap)+mmap->size+sizeof(multiboot_uint32_t)) 126 | wend 127 | end sub 128 | 129 | function pmm_alloc (zone as uinteger = PMM_ZONE_NORMAL) as any ptr 130 | dim ret as any ptr = nullptr 131 | 132 | select case (zone) 133 | case PMM_ZONE_NORMAL: 134 | '' try to satisfy the request from the normal-zone 135 | ret = pmm_alloc_normal() 136 | if (ret = nullptr) then 137 | '' if it didn't work, fall through to the DMA24-zone 138 | ret = pmm_alloc(PMM_ZONE_DMA24) 139 | end if 140 | case PMM_ZONE_DMA24: 141 | ret = pmm_alloc_dma24() 142 | case else: 143 | panic_error(!"PMM: Invalid zone specification!\n") 144 | end select 145 | 146 | if (ret <> nullptr) then free_mem -= PAGE_SIZE 147 | return ret 148 | end function 149 | 150 | sub pmm_free (addr as any ptr) 151 | if (cuint(addr) < 16*1024*1024) then 152 | pmm_free_dma24(addr) 153 | else 154 | pmm_free_normal(addr) 155 | end if 156 | free_mem += PAGE_SIZE 157 | end sub 158 | -------------------------------------------------------------------------------- /kernel/include/elf32.bi: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2013 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #pragma once 20 | 21 | type Elf32_Addr as uinteger 22 | type Elf32_Half as ushort 23 | type ELF32_Off as uinteger 24 | type Elf32_Sword as integer 25 | type Elf32_Word as uinteger 26 | type Elf32_Uchar as ubyte 27 | 28 | const ELF_MAGIC as uinteger = &h464C457F '' &h7F, 'E', 'L', 'F' 29 | 30 | const ELF_CLASS_NONE as ubyte = &h00 31 | const ELF_CLASS_32 as ubyte = &h01 '' 32bit file 32 | const ELF_CLASS_64 as ubyte = &h02 '' 64bit file 33 | 34 | const ELF_DATA_NONE as ubyte = &h00 35 | const ELF_DATA_2LSB as ubyte = &h01 36 | const ELF_DATA_2MSB as ubyte = &h02 37 | 38 | type ELF_IDENT_HEADER field=1 39 | EI_MAGIC(0 to 3) as ubyte 40 | EI_CLASS as ubyte '' 32 or 64 bit? 41 | EI_DATA as ubyte '' Little or Big Endian? 42 | EI_VERSION as ubyte '' same as e_version 43 | EI_PAD as uinteger '' reserved (zero) 44 | EI_PAD2 as uinteger '' reserved (zero) 45 | EI_NIDENT as ubyte '' size of the IDENT_HEADER 46 | end type 47 | 48 | '' for 32bit Processors: 49 | ' e_ident.EI_CLASS = ELF_CLASS_32 50 | ' e_ident.EI_DATA = ELF_DATA_2LSB 51 | ' e_machine = ELF_EM_386 52 | 53 | const ELF_ET_NONE as ushort = &h0000 '' no type 54 | const ELF_ET_REL as ushort = &h0001 '' relocatable 55 | const ELF_ET_EXEC as ushort = &h0002 '' executeable 56 | const ELF_ET_DYN as ushort = &h0003 '' Shared-Object-File 57 | const ELF_ET_CORE as ushort = &h0004 '' Corefile 58 | const ELF_ET_LOPROC as ushort = &hFF00 '' Processor-specific 59 | const ELF_ET_HIPROC as ushort = &h00FF '' Processor-specific 60 | 61 | const ELF_EM_NONE as ushort = &h0000 '' no type 62 | const ELF_EM_M32 as ushort = &h0001 '' AT&T WE 32100 63 | const ELF_EM_SPARC as ushort = &h0002 '' SPARC 64 | const ELF_EM_386 as ushort = &h0003 '' Intel 80386 65 | const ELF_EM_68K as ushort = &h0004 '' Motorola 68000 66 | const ELF_EM_88K as ushort = &h0005 '' Motorola 88000 67 | const ELF_EM_860 as ushort = &h0007 '' Intel 80860 68 | const ELF_EM_MIPS as ushort = &h0008 '' MIPS RS3000 69 | 70 | const ELF_EV_NONE as uinteger = &h00 '' invalid version 71 | const ELF_EV_CURRENT as uinteger = &h01 '' current version 72 | 73 | type Elf32_Ehdr field=1 74 | e_ident as ELF_IDENT_HEADER '' IDENT-HEADER (see above) 75 | e_type as Elf32_Half '' type of the ELF-file (relocatable, executeable, shared-object...) 76 | e_machine as Elf32_Half '' processor-type 77 | e_version as Elf32_Word '' ELF-version 78 | e_entry as Elf32_Addr '' virtual address of the entrypoint 79 | e_phoff as Elf32_Off '' offset of the program-header. zero if no program-header exists 80 | e_shoff as Elf32_Off '' offset of the section-header. zero if no section-header exists 81 | e_flags as Elf32_Word '' processor-specific flags 82 | e_ehsize as Elf32_Half '' size of the ELF-header 83 | e_phentsize as Elf32_Half '' size of one program-header entry 84 | e_phnum as Elf32_Half '' number of entries in the program-header. zero if no program-header exists 85 | e_shentsize as Elf32_Half '' size of one section-header entry 86 | e_shnum as Elf32_Half '' number of entries in the section-header. zero if no section-header exists 87 | e_shstrndex as Elf32_Half '' tells us which entry of the section-header is linked to the String-Table 88 | end type 89 | 90 | const ELF_PT_NULL as uinteger = &h00 '' invalid segment 91 | const ELF_PT_LOAD as uinteger = &h01 '' loadable segment 92 | const ELF_PT_DYNAMIC as uinteger = &h02 '' dynamic segment 93 | const ELF_PT_INTERP as uinteger = &h03 '' position of a zero-terminated string, which tells the interpreter 94 | const ELF_PT_NOTE as uinteger = &h04 '' universal segment 95 | const ELF_PT_SHLIB as uinteger = &h05 '' shared lib 96 | const ELF_PT_PHDIR as uinteger = &h06 '' tells position and size of the program-header 97 | const ELF_PT_LOPROC as uinteger = &h70000000 '' reserved 98 | const ELF_PT_HIPROC as uinteger = &h7FFFFFFF '' reserved 99 | 100 | const ELF_PF_X as uinteger = &h01 '' executeable segment 101 | const ELF_PF_W as uinteger = &h02 '' writeable segment 102 | const ELF_PF_R as uinteger = &h04 '' readable segment 103 | 104 | type Elf32_Phdr field=1 105 | p_type as Elf32_Word '' type of the segment (see constants above) 106 | p_offset as Elf32_Off '' offset of the segment (in the file) 107 | p_vaddr as Elf32_Addr '' virtual address to which we should copy the segment 108 | p_paddr as Elf32_Addr '' physical address 109 | p_filesz as Elf32_Word '' size of the segment in the file 110 | p_memsz as Elf32_Word '' size of the segment in memory 111 | p_flags as Elf32_Word '' flags (combination of constants above) 112 | p_align as Elf32_Word '' alignment. if zero or one, then no alignment is needed, otherwise the alignment has to be a power of two 113 | end type 114 | -------------------------------------------------------------------------------- /kernel/src/smp.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "smp.bi" 20 | #include "kernel.bi" 21 | #include "debug.bi" 22 | #include "apic.bi" 23 | #include "mem.bi" 24 | #include "vmm.bi" 25 | #include "pmm.bi" 26 | 27 | #define uint_sig(a,b,c,d) (asc(a) or (asc(b) shl 8) or (asc(c) shl 16) or (asc(d) shl 24)) 28 | 29 | const FP_SIGNATURE as uinteger = uint_sig("_", "M", "P", "_") 30 | const CT_SIGNATURE as uinteger = uint_sig("P", "C", "M", "P") 31 | 32 | function checksum (type_ptr as any ptr, size as uinteger) as ubyte 33 | dim checksum_byte as ubyte = 0 34 | dim bp as ubyte ptr = cast(ubyte ptr, type_ptr) 35 | 36 | for counter as uinteger = 0 to size-1 step 1 37 | checksum_byte += bp[counter] 38 | next counter 39 | 40 | return checksum_byte 41 | end function 42 | 43 | function find_floating_pointer_in_area (start as uinteger, size as uinteger) as smp_floating_pointer ptr 44 | dim floating_pointer as smp_floating_pointer ptr = cast(smp_floating_pointer ptr, start) 45 | 46 | while (cuint(floating_pointer) < (start + size)) 47 | '' signature found 48 | if (floating_pointer->signature = FP_SIGNATURE) then 49 | '' check checksum, sum of all bytes must be zero 50 | if (checksum(floating_pointer, sizeof(smp_floating_pointer)) = 0) then 51 | '' structure found, return address 52 | return floating_pointer 53 | end if 54 | end if 55 | '' not found yet, search some more 56 | '' the structure is located on a 16-byte boundary (which is also the size of the FP), so adding 1 is ok 57 | floating_pointer += 1 58 | wend 59 | '' structure not found 60 | return nullptr 61 | end function 62 | 63 | function find_floating_pointer () as smp_floating_pointer ptr 64 | dim floating_pointer as smp_floating_pointer ptr 65 | 66 | floating_pointer = find_floating_pointer_in_area(0, &h400) 67 | if (floating_pointer <> nullptr) then return floating_pointer 68 | 69 | floating_pointer = find_floating_pointer_in_area(&h9FC00, &h400) 70 | if (floating_pointer <> nullptr) then return floating_pointer 71 | 72 | floating_pointer = find_floating_pointer_in_area(&hF0000, &h10000) 73 | return floating_pointer 74 | end function 75 | 76 | '' these symbols are generated by the linker to mark the embedded binary 77 | extern trampoline_start alias "_binary_obj_trampoline_bin_start" as byte 78 | extern trampoline_end alias "_binary_obj_trampoline_bin_end" as byte 79 | 80 | sub smp_init () 81 | '' the trampoline is a flat binary embedded into the kernel, that needs 82 | '' to be copied to 0x1000 83 | dim v_mem as any ptr = vmm_kernel_automap(&h1000, PAGE_SIZE) 84 | memcpy(v_mem, @trampoline_start, (@trampoline_end) - (@trampoline_start)) 85 | vmm_kernel_unmap(v_mem, PAGE_SIZE) 86 | lapic_startup_ipi(&h1000) 87 | 88 | '' FIXME: 89 | '' This code was based on the old SMP-spec, which has been replaced by 90 | '' ACPI-tables and is not working on newer systems. It is however the only 91 | '' way of starting pre-ACPI SMP systems. 92 | '' We should either drop this code, or refactor it into a fallback. 93 | #if 0 94 | dim floating_pointer as smp_floating_pointer ptr = find_floating_pointer() 95 | dim config_table as smp_config_table ptr 96 | 97 | if (floating_pointer = nullptr) then 98 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"floating pointer not found\n") 99 | return 100 | end if 101 | 102 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"floating pointer found: %X\n", cuint(floating_pointer)) 103 | 104 | if (floating_pointer->features(0) = 0) then 105 | config_table = cast(any ptr, floating_pointer->config_table) 106 | 107 | if (config_table->signature <> CT_SIGNATURE) then 108 | printk(LOG_INFO !" -> signature of the config table is damaged!\n") 109 | return 110 | end if 111 | 112 | if (checksum(config_table, config_table->base_table_length) <> 0) then 113 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"checksum of the config table is wrong!\n") 114 | return 115 | end if 116 | 117 | '' pointer for the table 118 | dim entry as ubyte ptr = cast(ubyte ptr, cuint(config_table) + sizeof(smp_config_table)) 119 | dim num_procs as uinteger = 0 120 | 121 | for entry_count as uinteger = 0 to config_table->entry_count-1 step 1 122 | select case *entry 123 | '' processor 124 | case CT_ENTRY_TYPES.PROCESSOR: 125 | num_procs += 1 126 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"processor #%u found\n", num_procs) 127 | entry += sizeof(cte_processor) 128 | '' bus 129 | case CT_ENTRY_TYPES.BUS: 130 | entry += sizeof(cte_bus) 131 | ''io apic 132 | case CT_ENTRY_TYPES.IO_APIC: 133 | '' TODO: put all the APIC's in an array 134 | dim ioapic as cte_io_apic ptr = cast(cte_io_apic ptr, entry) 135 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"I/O APIC found, ID: %X", cuint(ioapic->id)) 136 | printk(LOG_INFO !", %X\n", cuint(ioapic->version)) 137 | ioapic_base = ioapic->address 138 | entry += sizeof(cte_io_apic) 139 | '' io interrupt assignment 140 | case CT_ENTRY_TYPES.IO_INTERRUPT_ASSIGNMENT: 141 | entry += sizeof(cte_io_interrupt_assignment) 142 | '' local interrupt assignment 143 | case CT_ENTRY_TYPES.LOCAL_INTERRUPT_ASSIGNMENT: 144 | entry += sizeof(cte_local_interrupt_assignment) 145 | '' something went wrong 146 | case else: 147 | printk(LOG_INFO COLOR_GREEN "SMP: " COLOR_RESET !"config table entries corrupt!\n") 148 | return 149 | end select 150 | next 151 | 152 | end if 153 | #endif 154 | end sub 155 | 156 | '' we don't do much more here because FROST can't handle multiple processors atm 157 | '' TODO: proper SMP support 158 | -------------------------------------------------------------------------------- /drivers/pci/src/main.bas: -------------------------------------------------------------------------------- 1 | #include "../../../kernel/include/syscall_defs.bi" 2 | #include "../../libfrost/frost.bi" 3 | 4 | const CONFIG_ADDRESS = &hCF8 5 | const CONFIG_DATA = &hCFC 6 | 7 | asm 8 | .global fb_ctor__main 9 | end asm 10 | 11 | '' request access to the textbuffer 12 | 'dim buffer as byte ptr 13 | ' 14 | 'asm 15 | ' mov eax, syscalls.SYSCALL_MEMORY_ALLOCATE_PHYSICAL 16 | ' mov ebx, 4096 17 | ' mov ecx, &hb8000 18 | ' int &h62 19 | ' mov [buffer], eax 20 | 'end asm 21 | 22 | declare sub printd (format_string as const zstring, ...) 23 | 24 | sub outl (port as ushort, value as integer) 25 | asm 26 | movw dx, [port] 27 | mov eax, [value] 28 | outd dx, eax 29 | end asm 30 | end sub 31 | 32 | function inl (port as ushort) as integer 33 | asm 34 | movw dx, [port] 35 | ind eax, dx 36 | mov [function], eax 37 | end asm 38 | end function 39 | 40 | function PciRead (bus as integer, dev as integer, func as integer, offset as integer) as integer 41 | dim addr as integer = &h80000000 or (bus shl 16) or (dev shl 11) or (func shl 8) or (offset and &hFC) 42 | outl(CONFIG_ADDRESS, addr) 43 | return inl(CONFIG_DATA) 44 | end function 45 | 46 | sub PciWrite (bus as integer, dev as integer, func as integer, offset as integer, value as integer) 47 | dim addr as integer = &h80000000 or (bus shl 16) or (dev shl 11) or (func shl 8) or (offset and &hFC) 48 | outl(CONFIG_ADDRESS, addr) 49 | outl(CONFIG_DATA, value) 50 | end sub 51 | 52 | function PciIsDevicePresent (bus as integer, dev as integer) as boolean 53 | dim value as integer = PciRead(bus, dev, 0, 0) 54 | dim vendor as integer = value and &hFFFF 55 | dim device as integer = (value shr 16) and &hFFFF 56 | 57 | if vendor <> &hFFFF then 58 | printd(!"%X:%X\n", vendor, device) 59 | return true 60 | end if 61 | 62 | return false 63 | end function 64 | 65 | printd(!"Requesting PCI port access...\n") 66 | frost_syscall_port_request(CONFIG_ADDRESS) 67 | frost_syscall_port_request(CONFIG_ADDRESS+1) 68 | frost_syscall_port_request(CONFIG_ADDRESS+2) 69 | frost_syscall_port_request(CONFIG_ADDRESS+3) 70 | frost_syscall_port_request(CONFIG_DATA) 71 | frost_syscall_port_request(CONFIG_DATA+1) 72 | frost_syscall_port_request(CONFIG_DATA+2) 73 | frost_syscall_port_request(CONFIG_DATA+3) 74 | 75 | printd(!"Done.\n") 76 | 77 | for x as integer = 0 to 32 78 | PciIsDevicePresent(0, x) 79 | next 80 | 81 | while true 82 | 'frost_syscall_thread_yield() 83 | wend 84 | 85 | asm jmp $ 86 | 87 | 88 | declare sub put_uint (number as uinteger, numerical_base as const ubyte = 10, minchars as const ubyte = 1, fillchar as ubyte = 32, lowercase as const boolean = false) 89 | declare sub put_int (number as integer, numerical_base as const ubyte = 10, minchars as const ubyte = 1, fillchar as const ubyte = 32) 90 | 91 | '' print one char 92 | sub putc (char as ubyte) 93 | dim chars (0 to 1) as ubyte 94 | chars(1) = 0 95 | chars(0) = char 96 | 97 | frost_syscall_43(@chars(0)) 98 | end sub 99 | 100 | sub printd (format_string as const zstring, ...) 101 | dim fstr as const ubyte ptr = cast(const ubyte ptr, @format_string) 102 | dim arg as any ptr = va_first() 103 | dim c as uinteger = 0 104 | dim is_format as boolean = false 105 | var format_minchars = 1 106 | var format_fillchar = asc(" ") 107 | 108 | while (fstr[c] <> 0) 109 | if (is_format) then 110 | select case fstr[c] 111 | case asc("%") 112 | putc(fstr[c]) 113 | is_format = false 114 | case asc("d"), asc("i") 115 | put_int(va_arg(arg, integer), 10, format_minchars, format_fillchar) 116 | arg = va_next(arg, integer) 117 | is_format = false 118 | case asc("u") 119 | put_uint(va_arg(arg, uinteger), 10, format_minchars, format_fillchar) 120 | arg = va_next(arg, uinteger) 121 | is_format = false 122 | case asc("x") 123 | put_uint(va_arg(arg, uinteger), 16, format_minchars, format_fillchar, true) 124 | arg = va_next(arg, uinteger) 125 | is_format = false 126 | case asc("X") 127 | put_uint(va_arg(arg, uinteger), 16, format_minchars, format_fillchar) 128 | arg = va_next(arg, uinteger) 129 | is_format = false 130 | case asc("c") 131 | putc(va_arg(arg, byte)) 132 | arg = va_next(arg, byte) 133 | is_format = false 134 | case asc("s") 135 | dim s_it as uinteger = 0 136 | dim s_str as byte ptr = va_arg(arg, byte ptr) 137 | arg = va_next(arg, byte ptr) 138 | 139 | while (s_str[s_it] <> 0) 140 | putc(s_str[s_it]) 141 | s_it += 1 142 | wend 143 | 144 | is_format = false 145 | case asc("0") to asc("9") 146 | if (fstr[c] = asc("0") and (fstr[c-1] = asc("%"))) then 147 | format_fillchar = asc("0") 148 | else 149 | format_minchars = format_minchars*10 + (fstr[c] - asc("0")) 150 | end if 151 | end select 152 | else 153 | select case fstr[c] 154 | case asc("%") 155 | is_format = true 156 | format_minchars = 1 157 | format_fillchar = asc(" ") 158 | case else 159 | putc(fstr[c]) 160 | end select 161 | end if 162 | 163 | c += 1 164 | wend 165 | end sub 166 | 167 | '' print an uinteger with a given base and at least as many digits as given in minchars 168 | sub put_uint (number as uinteger, numerical_base as const ubyte = 10, minchars as const ubyte = 1, fillchar as ubyte = 32, lowercase as const boolean = false) 169 | if ((numerical_base > 36) or (numerical_base < 2)) then return 170 | if (minchars = 1) then fillchar = asc("0") 171 | dim chars(1 to 10) as ubyte 172 | dim num as ubyte 173 | dim counter as uinteger = 10 174 | dim rem_chars as integer = minchars 175 | 176 | do 177 | chars(counter) = 48+(number mod numerical_base) 178 | if (chars(counter)>57) then chars(counter) += 7 179 | counter -= 1 180 | number \= numerical_base 181 | rem_chars -= 1 182 | loop until ((number <= 0) and (rem_chars <= 0)) 183 | 184 | for counter = 1 to 10 185 | if ((chars(counter)=0) and (num = 0)) then continue for 186 | if ((chars(counter)=asc("0")) and (num=0)) then 187 | putc(fillchar) 188 | else 189 | if (lowercase) and cast(boolean, (chars(counter) > 64)) then chars(counter) += 32 190 | putc(chars(counter)) 191 | num = 1 192 | end if 193 | next 194 | end sub 195 | 196 | '' same game with integers. if the number is negative we just print a minus and then the number. 197 | sub put_int (number as integer, numerical_base as const ubyte = 10, minchars as const ubyte = 1, fillchar as const ubyte = 32) 198 | if ((numerical_base > 36) or (numerical_base < 2)) then return 199 | if (number<0) then 200 | putc(45) 201 | number = -number 202 | end if 203 | put_uint(cuint(number),numerical_base,minchars,fillchar) 204 | end sub 205 | -------------------------------------------------------------------------------- /kernel/src/thread.bas: -------------------------------------------------------------------------------- 1 | /' 2 | ' FROST x86 microkernel 3 | ' Copyright (C) 2010-2017 Stefan Schmidt 4 | ' 5 | ' This program is free software: you can redistribute it and/or modify 6 | ' it under the terms of the GNU General Public License as published by 7 | ' the Free Software Foundation, either version 3 of the License, or 8 | ' (at your option) any later version. 9 | ' 10 | ' This program is distributed in the hope that it will be useful, 11 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ' GNU General Public License for more details. 14 | ' 15 | ' You should have received a copy of the GNU General Public License 16 | ' along with this program. If not, see . 17 | '/ 18 | 19 | #include "thread.bi" 20 | #include "process.bi" 21 | #include "pmm.bi" 22 | #include "vmm.bi" 23 | #include "kmm.bi" 24 | #include "mem.bi" 25 | #include "panic.bi" 26 | #include "video.bi" 27 | #include "modules.bi" 28 | 29 | DEFINE_LIST(thread_type) 30 | 31 | '' linked list of running threads 32 | dim shared running_threads_list as Listtype(thread_type) 33 | dim shared current_thread as thread_type ptr = nullptr 34 | dim shared idle_thread as thread_type ptr 35 | 36 | operator thread_type.new (size as uinteger) as any ptr 37 | return kmalloc(size) 38 | '' constructor is called automatically 39 | end operator 40 | 41 | operator thread_type.delete (buffer as any ptr) 42 | kfree(buffer) 43 | '' destructor is called automatically 44 | end operator 45 | 46 | constructor thread_type (process as process_type ptr, entry as any ptr, userstack_pages as uinteger, flags as ubyte = 0) 47 | '' assign id 48 | this.id = process->get_tid() 49 | 50 | '' set owning process 51 | this.parent_process = process 52 | 53 | '' set flags 54 | this.flags = flags 55 | 56 | '' set state 57 | this.state = THREAD_STATE_DISABLED 58 | 59 | '' insert it into the list of the process 60 | process->thread_list.insert_before(@this.process_threads) 61 | 62 | '' allocate a virtual memory area for the stack 63 | this.stack_area = process->a_s.allocate_area(userstack_pages) 64 | 65 | '' reserve physical memory and map the area 66 | for pagecounter as uinteger = 1 to userstack_pages 67 | dim p_addr as any ptr = pmm_alloc() 68 | dim v_addr as uinteger = cuint(this.stack_area->address) + (pagecounter-1)*PAGE_SIZE 69 | 70 | vmm_map_page(@process->context, cast(any ptr, v_addr), p_addr, VMM_FLAGS.USER_DATA) 71 | next 72 | 73 | '' reserve space for the kernel-stack 74 | this.kernelstack_p = pmm_alloc() 75 | 76 | '' map the kernel stack into the kernel's address space (unreachable from userspace) 77 | this.kernelstack_bottom = vmm_kernel_automap(this.kernelstack_p, PAGE_SIZE) 78 | 79 | '' create a pointer to the isf 80 | dim isf as interrupt_stack_frame ptr = this.kernelstack_bottom + PAGE_SIZE - sizeof(interrupt_stack_frame) 81 | this.isf = isf 82 | 83 | '' clear the whole structure 84 | memset(isf, 0, sizeof(interrupt_stack_frame)) 85 | 86 | '' initialize the isf 87 | isf->eflags = &h0202 88 | isf->eip = cuint(entry) 89 | isf->esp = cuint(this.stack_area->address) + this.stack_area->pages*PAGE_SIZE 90 | isf->cs = &h18 or &h03 91 | isf->ss = &h20 or &h03 92 | end constructor 93 | 94 | sub thread_type.destroy () 95 | if (current_thread = @this) then 96 | this.state = THREAD_STATE_KILL_ON_SCHEDULE 97 | this.flags or= THREAD_FLAG_RESCHEDULE 98 | return 99 | end if 100 | 101 | '' remove thread from the active thread list 102 | this.deactivate() 103 | 104 | '' remove thread from the threadlist of the process 105 | process_remove_thread(@this) 106 | 107 | '' unmap kernelstack 108 | vmm_unmap_range(@this.parent_process->context, this.kernelstack_bottom, 1) 109 | 110 | '' free kernelstack 111 | pmm_free(this.kernelstack_p) 112 | 113 | '' free the physical memory of the userspace stack 114 | for pagecounter as uinteger = 1 to this.stack_area->pages 115 | dim p_stack as any ptr = vmm_resolve(@this.parent_process->context, this.stack_area->address + (pagecounter-1)*PAGE_SIZE) 116 | pmm_free(p_stack) 117 | next 118 | 119 | '' unmap the userspace stack 120 | vmm_unmap_range(@this.parent_process->context, this.stack_area->address, this.stack_area->pages) 121 | 122 | '' delete the address space area 123 | delete this.stack_area 124 | 125 | '' free thread structure 126 | kfree(@this) 127 | end sub 128 | 129 | sub thread_type.activate () 130 | if (this.state = THREAD_STATE_RUNNING) then 131 | panic_error("Kernel tried to activate an already activated thread!") 132 | end if 133 | 134 | '' set the state 135 | this.state = THREAD_STATE_RUNNING 136 | 137 | '' insert it into the running-thread-list 138 | running_threads_list.insert_before(@this.active_threads) 139 | end sub 140 | 141 | sub thread_type.deactivate () 142 | this.state = THREAD_STATE_DISABLED 143 | 144 | this.active_threads.remove() 145 | end sub 146 | 147 | function schedule (isf as interrupt_stack_frame ptr) as thread_type ptr 148 | dim new_thread as thread_type ptr = current_thread 149 | 150 | dim it as Listtype(thread_type) ptr = iif(current_thread, @current_thread->active_threads, @running_threads_list) 151 | while (not running_threads_list.is_empty()) 152 | it = it->get_next() 153 | if (it = @running_threads_list) then continue while 154 | 155 | dim t as thread_type ptr = it->get_owner() 156 | 157 | if (t->state = THREAD_STATE_KILL_ON_SCHEDULE) then 158 | t->destroy() 159 | continue while 160 | end if 161 | 162 | new_thread = t 163 | exit while 164 | wend 165 | 166 | if (running_threads_list.is_empty()) then 167 | new_thread = idle_thread 168 | end if 169 | 170 | if (current_thread <> nullptr) then 171 | if (new_thread->parent_process <> current_thread->parent_process) then 172 | '' IO bitmaps are process-wide, so unload the bitmap on process switch 173 | tss_ptr->io_bitmap_offset = TSS_IO_BITMAP_NOT_LOADED 174 | end if 175 | end if 176 | 177 | current_thread = new_thread 178 | 179 | return new_thread 180 | end function 181 | 182 | sub thread_switch (isf as interrupt_stack_frame ptr) 183 | dim old_process as process_type ptr = nullptr 184 | if (get_current_thread() <> nullptr) then 185 | old_process = get_current_thread()->parent_process 186 | end if 187 | 188 | dim new_thread as thread_type ptr = schedule(isf) '' select a new thread 189 | 190 | '' set his esp0 in the tss 191 | tss_ptr->esp0 = cuint(new_thread->isf) + sizeof(interrupt_stack_frame) 192 | '' set the esp0 for fast syscalls 193 | write_msr(MSR_IA32_SYSENTER_ESP, cuint(new_thread->isf) + sizeof(interrupt_stack_frame)) 194 | 195 | '' load the new pagedir 196 | if ((new_thread->parent_process <> old_process) and (new_thread <> idle_thread)) then 197 | vmm_activate_context(@new_thread->parent_process->context) 198 | end if 199 | end sub 200 | 201 | function get_current_thread () as thread_type ptr 202 | return current_thread 203 | end function 204 | 205 | sub thread_idle () 206 | do 207 | asm hlt 208 | loop 209 | end sub 210 | 211 | sub thread_create_idle_thread () 212 | idle_thread = new thread_type(init_process, @thread_idle, 0) 213 | idle_thread->isf->cs = &h08 214 | idle_thread->isf->ss = &h10 215 | 216 | '' don't use thread_activate here, it's not a normal thread 217 | idle_thread->state = THREAD_STATE_RUNNING 218 | end sub 219 | 220 | sub set_io_bitmap () 221 | tss_ptr->io_bitmap_offset = TSS_IO_BITMAP_OFFSET 222 | 223 | if (current_thread->parent_process->io_bitmap <> nullptr) then 224 | memcpy(@tss_ptr->io_bitmap(0), current_thread->parent_process->io_bitmap, &hFFFF\8) 225 | else 226 | memset(@tss_ptr->io_bitmap(0), &hFF, &hFFFF\8) 227 | end if 228 | end sub 229 | --------------------------------------------------------------------------------