5650 - support a second OS: soso

https://github.com/ozkl/soso

+ Much smaller than Linux; builds instantly
+ Supports graphics
- No network support
- Doesn't work on a cloud server (yet?)
This commit is contained in:
Kartik Agaram 2019-09-14 01:42:29 -07:00
parent ded2b24ce2
commit 46bb1d3157
101 changed files with 33999 additions and 66 deletions

View File

@ -9,10 +9,10 @@ to run, and nothing else.
```sh
$ git clone https://github.com/akkartik/mu
$ cd mu
# package up a "hello world" binary and Linux kernel into mu.iso
$ ./gen_iso examples/ex6.subx
# package up a "hello world" binary and kernel into mu_soso.iso
$ ./gen_soso_iso init.soso examples/ex6.subx
# try it out
$ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d
$ qemu-system-i386 -cdrom mu_soso.iso
# print the message
```
@ -61,7 +61,7 @@ code. Here's a program (`examples/ex1.subx`) that returns 42:
You can generate tiny zero-dependency ELF binaries with it that run on Linux.
```sh
$ ./subx translate examples/ex1.subx -o examples/ex1 # on Linux or BSD or Mac
$ ./subx translate init.linux examples/ex1.subx -o examples/ex1 # on Linux or BSD or Mac
$ ./examples/ex1 # only on Linux
$ echo $?
42
@ -82,7 +82,7 @@ messages.
Emulated runs can generate a trace that permits [time-travel debugging](https://github.com/akkartik/mu/blob/master/browse_trace/Readme.md).
```sh
$ ./subx --debug translate examples/factorial.subx -o examples/factorial
$ ./subx --debug translate init.linux examples/factorial.subx -o examples/factorial
saving address->label information to 'labels'
saving address->source information to 'source_lines'
@ -104,23 +104,23 @@ You can use SubX to translate itself. For example, running natively on Linux:
```sh
# generate translator phases using the C++ translator
$ ./subx translate 0*.subx apps/subx-common.subx apps/hex.subx -o hex
$ ./subx translate 0*.subx apps/subx-common.subx apps/survey.subx -o survey
$ ./subx translate 0*.subx apps/subx-common.subx apps/pack.subx -o pack
$ ./subx translate 0*.subx apps/subx-common.subx apps/assort.subx -o assort
$ ./subx translate 0*.subx apps/subx-common.subx apps/dquotes.subx -o dquotes
$ ./subx translate 0*.subx apps/subx-common.subx apps/tests.subx -o tests
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/hex.subx -o hex
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/survey.subx -o survey
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/pack.subx -o pack
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/assort.subx -o assort
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/dquotes.subx -o dquotes
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/tests.subx -o tests
$ chmod +x hex survey pack assort dquotes tests
# use the generated translator phases to translate SubX programs
$ cat examples/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
$ cat init.linux examples/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
$ chmod +x a.elf
$ ./a.elf
$ echo $?
42
# or, automating the above steps
$ ./ntranslate ex1.subx
$ ./ntranslate init.linux ex1.subx
$ chmod +x a.elf
$ ./a.elf
$ echo $?
@ -130,27 +130,32 @@ You can use SubX to translate itself. For example, running natively on Linux:
Or, running in a VM on other platforms:
```sh
$ ./translate ex1.subx # generates identical a.elf to above
$ ./translate init.linux ex1.subx # generates identical a.elf to above
$ ./subx run a.elf
$ echo $?
42
```
Finally, as described at the top, you can turn it into a bootable disk image
containing just your code and a Linux kernel. You can run the disk image on a
cloud server that supports custom images. [Instructions for Linode.](http://akkartik.name/post/iso-on-linode)
As described at the start, you can package up SubX binaries with the minimal
hobbyist OS [soso](https://github.com/ozkl/soso) and run them on Qemu.
(Requires graphics. Currently doesn't work on a cloud server.)
```sh
$ ./gen_soso_iso init.soso examples/ex6.subx
$ qemu-system-i386 -cdrom mu_soso.iso
```
You can also package up SubX binaries with a Linux kernel and run them on
either Qemu or [a cloud server that supports custom images](http://akkartik.name/post/iso-on-linode).
(Takes 12 minutes with 8GB RAM. Requires 12 million LoC of C for the Linux
kernel; that number will gradually go down.)
```sh
$ sudo apt install build-essential flex bison wget libelf-dev libssl-dev xorriso
$ ./gen_iso examples/ex6.subx
$ ./gen_linux_iso init.linux examples/ex6.subx
$ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d
```
(`gen_iso` only came into existence 2019-08-09, and has a flabby laundry list
of dependencies that I will gradually prune. It currently takes 12 minutes to
run on a single core with 8 GB RAM, mostly to compile its fork of the Linux
kernel.)
## What it looks like
Here is the above example again:
@ -306,7 +311,7 @@ like decimal numbers.
Try running this example now:
```sh
$ ./subx translate examples/ex3.subx -o examples/ex3
$ ./subx translate init.linux examples/ex3.subx -o examples/ex3
$ ./subx run examples/ex3
$ echo $?
55
@ -847,6 +852,7 @@ Mu builds on many ideas that have come before, especially:
- Forth for demonstrating that ergonomics don't require grammar; and
- [Minimal Linux Live](http://minimal.linux-bg.org) for teaching how to create
a bootable disk image.
- [Soso](https://github.com/ozkl/soso), a tiny hackable OS.
## Coda

18
build
View File

@ -115,35 +115,37 @@ then
# Assumption: SubX programs don't need to be retranslated every time we
# rebuild the C++ bootstrap.
OS=${OS:-linux}
# simple example programs
for n in `seq 1 12`
do
older_than examples/ex$n 049init.linux examples/ex$n.subx && {
./subx_bin translate 049init.linux examples/ex$n.subx -o examples/ex$n
older_than examples/ex$n init.$OS examples/ex$n.subx && {
./subx_bin translate init.$OS examples/ex$n.subx -o examples/ex$n
}
done
# simple apps that use the standard library
for app in factorial crenshaw2-1 crenshaw2-1b handle
do
older_than apps/$app 049init.linux [0-9]*.subx && apps/$app.subx {
./subx_bin translate 049init.linux [0-9]*.subx apps/$app.subx -o apps/$app
older_than apps/$app init.$OS [0-9]*.subx apps/$app.subx && {
./subx_bin translate init.$OS [0-9]*.subx apps/$app.subx -o apps/$app
}
done
# self-hosting translator
for phase in hex survey pack assort dquotes tests
do
older_than apps/$phase 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
./subx_bin translate 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
older_than apps/$phase init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
./subx_bin translate init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
}
done
# higher-level syntax
for phase in sigils
do
older_than apps/$phase 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
./subx_bin translate 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
older_than apps/$phase init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
./subx_bin translate init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
}
done

3
clean
View File

@ -7,4 +7,5 @@ rm -rf .until
test $# -gt 0 && exit 0 # convenience: 'clean top-level' to leave subsidiary tools alone
rm -rf enumerate/enumerate tangle/tangle tangle/*_list */*.dSYM termbox/*.[oa]
rm -rf browse_trace/browse_trace_bin browse_trace/*_list
rm -rf tmp mu.iso
rm -rf tmp mu-linux.iso outfs initrd.fat mu-soso.iso
( cd kernel.soso && make clean; )

View File

@ -1,6 +1,6 @@
#!/bin/sh
# Build one or more .subx files into an ELF binary, and package it up into a
# bootable ISO image.
# bootable ISO image with a Linux kernel.
#
# Must be run on Linux.
#
@ -17,21 +17,23 @@ then
exit 1
fi
echo "=== constructing initramfs out of SubX binary"
echo "=== building SubX binary"
./ntranslate $*
mv a.elf init
chmod +x init
echo "=== constructing initramfs out of SubX binary"
rm -rf tmp/isoimage
mkdir -p tmp/isoimage/boot
echo init | cpio -R root:root -H newc -o | xz -9 --check=none > tmp/isoimage/boot/rootfs.xz
if [ ! -d kernel ]
then
echo "=== cloning kernel"
echo "=== cloning linux kernel"
git clone https://github.com/akkartik/kernel
fi
echo "=== building kernel"
echo "=== building linux kernel"
( cd kernel
make bzImage -j $(grep ^processor /proc/cpuinfo | wc -l)
)
@ -48,7 +50,7 @@ cp syslinux.cfg \
tmp/syslinux-*/bios/com32/elflink/ldlinux/ldlinux.c32 \
tmp/isoimage/boot/syslinux
echo "=== generating ISO"
echo "=== generating mu-linux.iso"
# 'hybrid' ISO can also be used on non-optical media such as a disk or USB stick
xorriso -as mkisofs \
-isohybrid-mbr tmp/syslinux-*/bios/mbr/isohdpfx.bin \
@ -57,4 +59,4 @@ xorriso -as mkisofs \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
tmp/isoimage -o mu.iso
tmp/isoimage -o mu_linux.iso

44
gen_soso_iso Executable file
View File

@ -0,0 +1,44 @@
#!/bin/sh
# Build one or more .subx files into an ELF binary, and package it up into a
# bootable ISO image with a Soso (https://github.com/ozkl/soso) kernel.
#
# Must be run on Linux.
#
# Soso is published under the 2-clause BSD license.
set -e
if [ $# -eq 0 ]
then
echo "Usage: `basename $0` file.subx ..."
exit 1
fi
echo "=== building SubX binary"
./ntranslate $*
mv a.elf init
chmod +x init
echo "=== constructing initramfs out of SubX binary"
dd if=/dev/zero of=initrd.fat bs=8M count=1
LOOP=`losetup -f`
sudo losetup $LOOP initrd.fat
sudo mkfs.vfat $LOOP
sudo mount $LOOP /mnt
cp init /mnt/
umount /mnt
losetup -d $LOOP
sync
chown $SUDO_USER:$SUDO_USER initrd.fat
echo "=== building soso kernel"
( cd kernel.soso
make
)
echo "=== generating mu-soso.iso"
mkdir -p outfs/boot/grub
cp kernel.soso/grub.cfg outfs/boot/grub
cp kernel.soso/kernel.bin outfs/boot/
cp initrd.fat outfs/boot/
grub-mkrescue -o mu_soso.iso outfs

40
init.soso Normal file
View File

@ -0,0 +1,40 @@
# Some OS-specific preliminaries for Soso.
# Memory layout
#
# 0x40000000 - 0x40001ffff - for ELF code+data
# 0x40002000 - 0x401ffffff - for heap
== code 0x40000000
== data 0x40001000
# Syscalls
#
# We don't have libc, so we need to know Soso's precise syscall layout.
# https://github.com/ozkl/soso/blob/master/kernel/syscalltable.h
== code
syscall_exit: # status/ebx : int
b8/copy-to-eax 8/imm32
cd/syscall 0x80/imm8
syscall_read: # fd/ebx : int, buf/ecx : address, size/edx : int -> nbytes-or-error/eax : int
b8/copy-to-eax 2/imm32
cd/syscall 0x80/imm8
c3/return
syscall_write: # fd/ebx : int, buf/ecx : address, size/edx : int -> nbytes-or-error/eax : int
b8/copy-to-eax 3/imm32
cd/syscall 0x80/imm8
c3/return
syscall_open: # filename/ebx : (address null-terminated-string), flags/ecx : int -> fd-or-error/eax : int
b8/copy-to-eax 0/imm32
cd/syscall 0x80/imm8
c3/return
syscall_close: # fd/ebx : int -> status/eax
b8/copy-to-eax 1/imm32
cd/syscall 0x80/imm8
c3/return
# anonymous mmap not implemented

25
kernel.soso/LICENSE Normal file
View File

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2017, ozkl
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

19
kernel.soso/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC=cc
LD=ld
CFLAGS=-nostdlib -nostdinc -fno-builtin -m32 -c
LDFLAGS=-Tlink.ld -m elf_i386
ASFLAGS=-felf
OBJ = $(patsubst %.c,%.o,$(wildcard *.c)) $(patsubst %.asm,%.o,$(wildcard *.asm))
kernel.bin: $(OBJ)
$(LD) $(LDFLAGS) -o kernel.bin $(OBJ) font/font.o
%.o:%.c
$(CC) $(CFLAGS) $< -o $@
%.o:%.asm
nasm $(ASFLAGS) $< -o $@
clean:
-rm *.o kernel.bin

1
kernel.soso/Readme Normal file
View File

@ -0,0 +1 @@
Fork of https://github.com/ozkl/soso at git hash c7bde44ffb8f081d68b5ae61444d419539475833.

257
kernel.soso/alloc.c Normal file
View File

@ -0,0 +1,257 @@
#include "common.h"
#include "screen.h"
#include "alloc.h"
#include "vmm.h"
#include "process.h"
#include "debugprint.h"
#define KMALLOC_MINSIZE 16
extern uint32 *gKernelPageDirectory;
static char *gKernelHeap = NULL;
static uint32 gKernelHeapUsed = 0;
void initializeKernelHeap()
{
gKernelHeap = (char *) KERN_HEAP_BEGIN;
ksbrkPage(1);
}
void *ksbrkPage(int n)
{
struct MallocHeader *chunk;
char *p_addr;
int i;
if ((gKernelHeap + (n * PAGESIZE_4M)) > (char *) KERN_HEAP_END) {
//Screen_PrintF("ERROR: ksbrk(): no virtual memory left for kernel heap !\n");
return (char *) -1;
}
chunk = (struct MallocHeader *) gKernelHeap;
for (i = 0; i < n; i++)
{
p_addr = getPageFrame4M();
//Screen_PrintF("DEBUG: ksbrkPage(): got 4M on physical %x\n", p_addr);
if ((int)(p_addr) < 0)
{
PANIC("PANIC: ksbrkPage(): no free page frame available !");
return (char *) -1;
}
addPageToPd(gKernelPageDirectory, gKernelHeap, p_addr, 0); //add PG_USER to allow user programs to read kernel heap
gKernelHeap += PAGESIZE_4M;
}
chunk->size = PAGESIZE_4M * n;
chunk->used = 0;
return chunk;
}
void *kmalloc(uint32 size)
{
if (size==0)
return 0;
unsigned long realsize;
struct MallocHeader *chunk, *other;
if ((realsize = sizeof(struct MallocHeader) + size) < KMALLOC_MINSIZE)
{
realsize = KMALLOC_MINSIZE;
}
chunk = (struct MallocHeader *) KERN_HEAP_BEGIN;
while (chunk->used || chunk->size < realsize)
{
if (chunk->size == 0)
{
printkf("\nPANIC: kmalloc(): corrupted chunk on %x with null size (heap %x) !\nSystem halted\n", chunk, gKernelHeap);
PANIC("kmalloc()");
return 0;
}
chunk = (struct MallocHeader *)((char *)chunk + chunk->size);
if (chunk == (struct MallocHeader *) gKernelHeap)
{
if ((int)(ksbrkPage((realsize / PAGESIZE_4M) + 1)) < 0)
{
PANIC("kmalloc(): no memory left for kernel !\nSystem halted\n");
return 0;
}
}
else if (chunk > (struct MallocHeader *) gKernelHeap)
{
printkf("\nPANIC: kmalloc(): chunk on %x while heap limit is on %x !\nSystem halted\n", chunk, gKernelHeap);
PANIC("kmalloc()");
return 0;
}
}
if (chunk->size - realsize < KMALLOC_MINSIZE)
{
chunk->used = 1;
}
else
{
other = (struct MallocHeader *)((char *) chunk + realsize);
other->size = chunk->size - realsize;
other->used = 0;
chunk->size = realsize;
chunk->used = 1;
}
gKernelHeapUsed += realsize;
return (char *) chunk + sizeof(struct MallocHeader);
}
void kfree(void *v_addr)
{
if (v_addr==(void*)0)
return;
struct MallocHeader *chunk, *other;
chunk = (struct MallocHeader *)((uint32)v_addr - sizeof(struct MallocHeader));
chunk->used = 0;
gKernelHeapUsed -= chunk->size;
//Merge free block with next free block
while ((other = (struct MallocHeader *)((char *)chunk + chunk->size))
&& other < (struct MallocHeader *)gKernelHeap
&& other->used == 0)
{
chunk->size += other->size;
}
}
static void sbrkPage(Process* process, int pageCount)
{
if (pageCount > 0)
{
for (int i = 0; i < pageCount; ++i)
{
if ((process->heapNextUnallocatedPageBegin + PAGESIZE_4M) > (char*)USER_OFFSET_END)
{
return;
}
char * p_addr = getPageFrame4M();
if ((int)(p_addr) < 0)
{
//PANIC("sbrkPage(): no free page frame available !");
return;
}
addPageToPd(process->pd, process->heapNextUnallocatedPageBegin, p_addr, PG_USER);
process->heapNextUnallocatedPageBegin += PAGESIZE_4M;
}
}
else if (pageCount < 0)
{
pageCount *= -1;
for (int i = 0; i < pageCount; ++i)
{
if (process->heapNextUnallocatedPageBegin - PAGESIZE_4M >= process->heapBegin)
{
process->heapNextUnallocatedPageBegin -= PAGESIZE_4M;
//This also releases the page frame
removePageFromPd(process->pd, process->heapNextUnallocatedPageBegin, TRUE);
}
}
}
}
void initializeProcessHeap(Process* process)
{
process->heapBegin = (char*) USER_OFFSET;
process->heapEnd = process->heapBegin;
process->heapNextUnallocatedPageBegin = process->heapBegin;
//Userland programs (their code, data,..) start from USER_OFFSET
//So we should leave some space for them by moving heap pointer.
//As a result userspace malloc functions start from a forward point (+ USER_EXE_IMAGE).
sbrk(process, USER_EXE_IMAGE);
}
void *sbrk(Process* process, int nBytes)
{
printkf("sbrk:1: pid:%d nBytes:%d\n", process->pid, nBytes);
char* previousBreak = process->heapEnd;
printkf("before: %x\n", previousBreak);
if (nBytes > 0)
{
int remainingInThePage = process->heapNextUnallocatedPageBegin - process->heapEnd;
//Screen_PrintF("sbrk:2: remainingInThePage:%d\n", remainingInThePage);
if (nBytes > remainingInThePage)
{
int bytesNeededInNewPages = nBytes - remainingInThePage;
int neededNewPageCount = (bytesNeededInNewPages / PAGESIZE_4M) + 1;
//Screen_PrintF("sbrk:3: neededNewPageCount:%d\n", neededNewPageCount);
uint32 freePages = getFreePageCount();
if ((uint32)neededNewPageCount + 1 > freePages)
{
return (void*)-1;
}
sbrkPage(process, neededNewPageCount);
}
}
else if (nBytes < 0)
{
char* currentPageBegin = process->heapNextUnallocatedPageBegin - PAGESIZE_4M;
int remainingInThePage = process->heapEnd - currentPageBegin;
//Screen_PrintF("sbrk:4: remainingInThePage:%d\n", remainingInThePage);
if (-nBytes > remainingInThePage)
{
int bytesInPreviousPages = -nBytes - remainingInThePage;
int neededNewPageCount = (bytesInPreviousPages / PAGESIZE_4M) + 1;
//Screen_PrintF("sbrk:5: neededNewPageCount:%d\n", neededNewPageCount);
sbrkPage(process, -neededNewPageCount);
}
}
process->heapEnd += nBytes;
printkf("after: %x\n", process->heapEnd);
return previousBreak;
}
uint32 getKernelHeapUsed()
{
return gKernelHeapUsed;
}

25
kernel.soso/alloc.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef ALLOC_H
#define ALLOC_H
#include "common.h"
#include "process.h"
void initializeKernelHeap();
void *ksbrkPage(int n);
void *kmalloc(uint32 size);
void kfree(void *v_addr);
void initializeProcessHeap(Process* process);
void *sbrk(Process* process, int nBytes);
uint32 getKernelHeapUsed();
struct MallocHeader
{
unsigned long size:31;
unsigned long used:1;
} __attribute__ ((packed));
typedef struct MallocHeader MallocHeader;
#endif // ALLOC_H

51
kernel.soso/boot.asm Normal file
View File

@ -0,0 +1,51 @@
MBOOT_PAGE_ALIGN equ 1<<0
MBOOT_MEM_INFO equ 1<<1
MBOOT_USE_GFX equ 1<<2
MBOOT_HEADER_MAGIC equ 0x1BADB002
MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO | MBOOT_USE_GFX
MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)
[BITS 32]
section .multiboot
align 4
dd MBOOT_HEADER_MAGIC
dd MBOOT_HEADER_FLAGS
dd MBOOT_CHECKSUM
dd 0x00000000 ; header_addr
dd 0x00000000 ; load_addr
dd 0x00000000 ; load_end_addr
dd 0x00000000 ; bss_end_addr
dd 0x00000000 ; entry_addr
; Graphics requests
dd 0x00000000 ; 0 = linear graphics
dd 1024
dd 768
dd 32
section .bss
align 16
stack_bottom:
resb 16384 ; 16 KiB
stack_top:
[GLOBAL _start] ; this is the entry point. we tell linker script to set start address of kernel elf file.
[EXTERN kmain]
section .text
_start:
mov esp, stack_top
; push multiboot parameter to kmain()
push ebx
; ...and run!
cli
call kmain
;never reach here
cli
hlt

441
kernel.soso/common.c Normal file
View File

@ -0,0 +1,441 @@
#include "common.h"
#include "screen.h"
#include "ttydriver.h"
static BOOL gInterruptsWereEnabled = FALSE;
// Write a byte out to the specified port.
void outb(uint16 port, uint8 value)
{
asm volatile ("outb %1, %0" : : "dN" (port), "a" (value));
}
void outw(uint16 port, uint16 value)
{
asm volatile ("outw %1, %0" : : "dN" (port), "a" (value));
}
uint8 inb(uint16 port)
{
uint8 ret;
asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
uint16 inw(uint16 port)
{
uint16 ret;
asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
return ret;
}
// Copy len bytes from src to dest.
void* memcpy(uint8 *dest, const uint8 *src, uint32 len)
{
const uint8 *sp = (const uint8 *)src;
uint8 *dp = (uint8 *)dest;
for(; len != 0; len--) *dp++ = *sp++;
return dest;
}
// Write len copies of val into dest.
void* memset(uint8 *dest, uint8 val, uint32 len)
{
uint8 *temp = (uint8 *)dest;
for ( ; len != 0; len--) *temp++ = val;
return dest;
}
void* memmove(void* dest, const void* src, uint32 n)
{
uint8* _dest;
uint8* _src;
if ( dest < src ) {
_dest = ( uint8* )dest;
_src = ( uint8* )src;
while ( n-- ) {
*_dest++ = *_src++;
}
} else {
_dest = ( uint8* )dest + n;
_src = ( uint8* )src + n;
while ( n-- ) {
*--_dest = *--_src;
}
}
return dest;
}
int memcmp( const void* p1, const void* p2, uint32 c )
{
const uint8* su1, *su2;
int8 res = 0;
for ( su1 = p1, su2 = p2; 0 < c; ++su1, ++su2, c-- ) {
if ( ( res = *su1 - *su2 ) != 0 ) {
break;
}
}
return res;
}
// Compare two strings. Should return -1 if
// str1 < str2, 0 if they are equal or 1 otherwise.
int strcmp(const char *str1, const char *str2)
{
int i = 0;
int failed = 0;
while(str1[i] != '\0' && str2[i] != '\0')
{
if(str1[i] != str2[i])
{
failed = 1;
break;
}
i++;
}
if ((str1[i] == '\0' && str2[i] != '\0') || (str1[i] != '\0' && str2[i] == '\0'))
{
failed = 1;
}
return failed;
}
int strncmp(const char *str1, const char *str2, int length)
{
for (int i = 0; i < length; ++i)
{
if (str1[i] != str2[i])
{
return str1[i] - str2[i];
}
}
return 0;
}
// Copy the NULL-terminated string src into dest, and
// return dest.
char *strcpy(char *dest, const char *src)
{
do
{
*dest++ = *src++;
}
while (*src != 0);
*dest = '\0';
return dest;
}
char *strcpyNonNull(char *dest, const char *src)
{
do
{
*dest++ = *src++;
}
while (*src != 0);
return dest;
}
//Copies the first num characters of source to destination. If the end of the source C string is found before num characters have been copied,
//destination is padded with zeros until a total of num characters have been written to it.
//No null-character is implicitly appended at the end of destination if source is longer than num.
//Thus, in this case, destination shall not be considered a null terminated C string.
char *strncpy(char *dest, const char *src, uint32 num)
{
BOOL sourceEnded = FALSE;
for (uint32 i = 0; i < num; ++i)
{
if (sourceEnded == FALSE && src[i] == '\0')
{
sourceEnded = TRUE;
}
if (sourceEnded)
{
dest[i] = '\0';
}
else
{
dest[i] = src[i];
}
}
return dest;
}
char* strcat(char *dest, const char *src)
{
size_t i,j;
for (i = 0; dest[i] != '\0'; i++)
;
for (j = 0; src[j] != '\0'; j++)
dest[i+j] = src[j];
dest[i+j] = '\0';
return dest;
}
int strlen(const char *src)
{
int i = 0;
while (*src++)
i++;
return i;
}
int strFirstIndexOf(const char *src, char c)
{
int i = 0;
while (src[i])
{
if (src[i] == c)
{
return i;
}
i++;
}
return -1;
}
uint32 rand()
{
static uint32 x = 123456789;
static uint32 y = 362436069;
static uint32 z = 521288629;
static uint32 w = 88675123;
uint32 t;
t = x ^ (x << 11);
x = y; y = z; z = w;
return w = w ^ (w >> 19) ^ t ^ (t >> 8);
}
int atoi(char *str)
{
int result = 0;
for (int i = 0; str[i] != '\0'; ++i)
{
result = result*10 + str[i] - '0';
}
return result;
}
void itoa (char *buf, int base, int d)
{
char *p = buf;
char *p1, *p2;
unsigned long ud = d;
int divisor = 10;
if (base == 'd' && d < 0)
{
*p++ = '-';
buf++;
ud = -d;
}
else if (base == 'x')
{
divisor = 16;
}
do
{
int remainder = ud % divisor;
*p++ = (remainder < 10) ? remainder + '0' : remainder + 'A' - 10;
}
while (ud /= divisor);
*p = 0;
//Reverse BUF.
p1 = buf;
p2 = p - 1;
while (p1 < p2)
{
char tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2--;
}
}
int sprintf_va(char* buffer, const char *format, __builtin_va_list vl)
{
char c;
char buf[20];
int bufferIndex = 0;
while ((c = *format++) != 0)
{
if (c != '%')
buffer[bufferIndex++] = c;
else
{
char *p;
c = *format++;
switch (c)
{
case 'x':
buf[0] = '0';
buf[1] = 'x';
//itoa (buf + 2, c, *((int *) arg++));
itoa (buf + 2, c, __builtin_va_arg(vl, int));
p = buf;
goto string;
break;
case 'd':
case 'u':
//itoa (buf, c, *((int *) arg++));
itoa (buf, c, __builtin_va_arg(vl, int));
p = buf;
goto string;
break;
case 's':
//p = *arg++;
p = __builtin_va_arg(vl, char*);
if (! p)
p = "(null)";
string:
while (*p)
buffer[bufferIndex++] = (*p++);
break;
default:
//buffer[bufferIndex++] = (*((int *) arg++));
buffer[bufferIndex++] = __builtin_va_arg(vl, int);
break;
}
}
}
buffer[bufferIndex] = '\0';
return bufferIndex;
}
int sprintf(char* buffer, const char *format, ...)
{
int result = 0;
__builtin_va_list vl;
__builtin_va_start(vl, format);
result = sprintf_va(buffer, format, vl);
__builtin_va_end(vl);
return result;
}
void printkf(const char *format, ...)
{
char buffer[1024];
buffer[0] = 'k';
buffer[1] = ':';
buffer[2] = 0;
Tty* tty = getActiveTTY();
if (tty)
{
__builtin_va_list vl;
__builtin_va_start(vl, format);
sprintf_va(buffer+2, format, vl);
__builtin_va_end(vl);
Tty_PutText(tty, buffer);
if (tty->flushScreen)
{
tty->flushScreen(tty);
}
}
}
void panic(const char *message, const char *file, uint32 line)
{
disableInterrupts();
printkf("PANIC:%s:%d:%s\n", file, line, message);
halt();
}
void warning(const char *message, const char *file, uint32 line)
{
printkf("WARNING:%s:%d:%s\n", file, line, message);
}
void panic_assert(const char *file, uint32 line, const char *desc)
{
disableInterrupts();
printkf("ASSERTION-FAILED:%s:%d:%s\n", file, line, desc);
halt();
}
uint32 readEsp()
{
uint32 stack_pointer;
asm volatile("mov %%esp, %0" : "=r" (stack_pointer));
return stack_pointer;
}
uint32 getCpuFlags()
{
uint32 eflags = 0;
asm("pushfl; pop %%eax; mov %%eax, %0": "=m"(eflags):);
return eflags;
}
BOOL isInterruptsEnabled()
{
uint32 eflags = getCpuFlags();
uint32 interruptFlag = 0x200; //9th flag
return (eflags & interruptFlag) == interruptFlag;
}
void beginCriticalSection()
{
gInterruptsWereEnabled = isInterruptsEnabled();
disableInterrupts();
}
void endCriticalSection()
{
if (gInterruptsWereEnabled)
{
enableInterrupts();
}
}

125
kernel.soso/common.h Normal file
View File

@ -0,0 +1,125 @@
#ifndef COMMON_H
#define COMMON_H
#define enableInterrupts() asm volatile("sti")
#define disableInterrupts() asm volatile("cli")
#define halt() asm volatile("hlt")
typedef unsigned long long uint64;
typedef signed long long int64;
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef short int16;
typedef unsigned char uint8;
typedef char int8;
typedef unsigned int size_t;
#define BOOL uint8
#define TRUE 1
#define FALSE 0
#define NULL 0
#define KERN_PAGE_DIRECTORY 0x00001000
#define KERN_BASE 0x00100000
//16M is identity mapped as below.
//First 8M we don't touch. Kernel code is there.
//4M is reserved for 4K page directories.
//4M is not used for now. kernel mini heap was here in old times.
#define RESERVED_AREA 0x01000000 //16 mb
#define KERN_PD_AREA_BEGIN 0x00800000 // 8 mb
#define KERN_PD_AREA_END 0x00C00000 //12 mb
#define KERN_NOTUSED_BEGIN 0x00C00000 //12 mb
#define KERN_NOTUSED_END 0x01000000 //16 mb
#define GFX_MEMORY 0x01000000 //16 mb
#define KERN_HEAP_BEGIN 0x02000000 //32 mb
#define KERN_HEAP_END 0x40000000 // 1 gb
#define PAGE_INDEX_4K(addr) ((addr) >> 12)
#define PAGE_INDEX_4M(addr) ((addr) >> 22)
#define PAGING_FLAG 0x80000000 // CR0 - bit 31
#define PSE_FLAG 0x00000010 // CR4 - bit 4
#define PG_PRESENT 0x00000001 // page directory / table
#define PG_WRITE 0x00000002
#define PG_USER 0x00000004
#define PG_4MB 0x00000080
#define PAGESIZE_4K 0x00001000
#define PAGESIZE_4M 0x00400000
#define RAM_AS_4K_PAGES 0x100000
#define RAM_AS_4M_PAGES 1024
#define KERNELMEMORY_PAGE_COUNT 256 //(KERN_HEAP_END / PAGESIZE_4M)
#define KERN_STACK_SIZE PAGESIZE_4K
//KERN_HEAP_END ends and this one starts
#define USER_OFFSET 0x40000000
#define USER_OFFSET_END 0xF0000000
#define USER_OFFSET_MMAP 0xF0000000
#define USER_OFFSET_MMAP_END 0xFFFFFFFF
#define USER_EXE_IMAGE 0x200000 //2MB
#define USER_ARGV_ENV_SIZE 0x10000 //65KB
#define USER_ARGV_ENV_LOC (USER_OFFSET + (USER_EXE_IMAGE - USER_ARGV_ENV_SIZE))
//This means we support executable images up to 2MB
//And user malloc functions will start from USER_OFFSET + USER_EXE_IMAGE
//We will 65KB (0x10000) for argv and environ just before user malloc start
//So USER_EXE_IMAGE - USER_ARGV_ENV_SIZE = 0x1F0000
//That means argv and env data will start from USER_OFFSET + 0x1F0000
//Of course libc should know this numbers :)
#define USER_STACK 0xF0000000
void outb(uint16 port, uint8 value);
void outw(uint16 port, uint16 value);
uint8 inb(uint16 port);
uint16 inw(uint16 port);
#define PANIC(msg) panic(msg, __FILE__, __LINE__);
#define WARNING(msg) warning(msg, __FILE__, __LINE__);
#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
void warning(const char *message, const char *file, uint32 line);
void panic(const char *message, const char *file, uint32 line);
void panic_assert(const char *file, uint32 line, const char *desc);
void* memset(uint8 *dest, uint8 val, uint32 len);
void* memcpy(uint8 *dest, const uint8 *src, uint32 len);
void* memmove(void* dest, const void* src, uint32 n);
int memcmp(const void* p1, const void* p2, uint32 c);
int strcmp(const char *str1, const char *str2);
int strncmp(const char *str1, const char *str2, int length);
char *strcpy(char *dest, const char *src);
char *strcpyNonNull(char *dest, const char *src);
char *strncpy(char *dest, const char *src, uint32 num);
char* strcat(char *dest, const char *src);
int strlen(const char *src);
int strFirstIndexOf(const char *src, char c);
int sprintf(char* buffer, const char *format, ...);
void printkf(const char *format, ...);
int atoi(char *str);
void itoa(char *buf, int base, int d);
uint32 rand();
uint32 readEip();
uint32 readEsp();
uint32 getCpuFlags();
BOOL isInterruptsEnabled();
void beginCriticalSection();
void endCriticalSection();
#endif // COMMON_H

21
kernel.soso/commonuser.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef COMMONUSER_H
#define COMMONUSER_H
typedef struct SosoMessage
{
int messageType;
int parameter1;
int parameter2;
int parameter3;
} SosoMessage;
typedef struct TtyUserBuffer
{
unsigned short lineCount;
unsigned short columnCount;
unsigned short currentLine;
unsigned short currentColumn;
unsigned char* buffer;
} TtyUserBuffer;
#endif // COMMONUSER_H

86
kernel.soso/debugprint.c Normal file
View File

@ -0,0 +1,86 @@
#include "debugprint.h"
#include "common.h"
#include "fs.h"
static File* gFile = NULL;
void Debug_initialize(const char* fileName)
{
FileSystemNode* node = getFileSystemNode(fileName);
gFile = open_fs(node, 0);
}
void Debug_PrintF(const char *format, ...)
{
char **arg = (char **) &format;
char c;
char buf[20];
char buffer[512];
int bufferIndex = 0;
//arg++;
__builtin_va_list vl;
__builtin_va_start(vl, format);
while ((c = *format++) != 0)
{
if (bufferIndex > 510)
{
break;
}
if (c != '%')
buffer[bufferIndex++] = c;
else
{
char *p;
c = *format++;
switch (c)
{
case 'x':
buf[0] = '0';
buf[1] = 'x';
//itoa (buf + 2, c, *((int *) arg++));
itoa (buf + 2, c, __builtin_va_arg(vl, int));
p = buf;
goto string;
break;
case 'd':
case 'u':
//itoa (buf, c, *((int *) arg++));
itoa (buf, c, __builtin_va_arg(vl, int));
p = buf;
goto string;
break;
case 's':
//p = *arg++;
p = __builtin_va_arg(vl, char*);
if (! p)
p = "(null)";
string:
while (*p)
buffer[bufferIndex++] = (*p++);
break;
default:
//buffer[bufferIndex++] = (*((int *) arg++));
buffer[bufferIndex++] = __builtin_va_arg(vl, int);
break;
}
}
}
buffer[bufferIndex] = '\0';
if (gFile)
{
write_fs(gFile, strlen(buffer), (uint8*)buffer);
}
__builtin_va_end(vl);
}

7
kernel.soso/debugprint.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef DEBUGPRINT_H
#define DEBUGPRINT_H
void Debug_initialize(const char* fileName);
void Debug_PrintF(const char *format, ...);
#endif // DEBUGPRINT_H

View File

@ -0,0 +1,211 @@
#include "screen.h"
#include "common.h"
#include "descriptortables.h"
#include "isr.h"
#include "process.h"
extern void flushGdt(uint32);
extern void flushIdt(uint32);
extern void flushTss();
static void initializeGdt();
static void initializeIdt();
static void setGdtEntry(int32 num, uint32 base, uint32 limit, uint8 access, uint8 gran);
static void setIdtEntry(uint8 num, uint32 base, uint16 sel, uint8 flags);
GdtEntry gGdtEntries[6];
GdtPointer gGdtPointer;
IdtEntry gIdtEntries[256];
IdtPointer gIdtPointer;
Tss gTss;
extern IsrFunction gInterruptHandlers[];
static void handleDoubleFault(Registers *regs);
static void handleGeneralProtectionFault(Registers *regs);
void initializeDescriptorTables()
{
initializeGdt();
initializeIdt();
memset((uint8*)&gInterruptHandlers, 0, sizeof(IsrFunction)*256);
registerInterruptHandler(8, handleDoubleFault);
registerInterruptHandler(13, handleGeneralProtectionFault);
}
static void initializeGdt()
{
gGdtPointer.limit = (sizeof(GdtEntry) * 6) - 1;
gGdtPointer.base = (uint32)&gGdtEntries;
setGdtEntry(0, 0, 0, 0, 0); // 0x00 Null segment
setGdtEntry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // 0x08 Code segment
setGdtEntry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // 0x10 Data segment
setGdtEntry(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // 0x18 User mode code segment
setGdtEntry(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // 0x20 User mode data segment
//TSS
memset((uint8*)&gTss, 0, sizeof(gTss));
gTss.debug_flag = 0x00;
gTss.io_map = 0x00;
gTss.esp0 = 0;//0x1FFF0;
gTss.ss0 = 0x10;//0x18;
gTss.cs = 0x0B; //from ring 3 - 0x08 | 3 = 0x0B
gTss.ss = gTss.ds = gTss.es = gTss.fs = gTss.gs = 0x13; //from ring 3 = 0x10 | 3 = 0x13
uint32 tss_base = (uint32) &gTss;
uint32 tss_limit = tss_base + sizeof(gTss);
setGdtEntry(5, tss_base, tss_limit, 0xE9, 0x00);
flushGdt((uint32)&gGdtPointer);
flushTss();
}
// Set the value of one GDT entry.
static void setGdtEntry(int32 num, uint32 base, uint32 limit, uint8 access, uint8 gran)
{
gGdtEntries[num].base_low = (base & 0xFFFF);
gGdtEntries[num].base_middle = (base >> 16) & 0xFF;
gGdtEntries[num].base_high = (base >> 24) & 0xFF;
gGdtEntries[num].limit_low = (limit & 0xFFFF);
gGdtEntries[num].granularity = (limit >> 16) & 0x0F;
gGdtEntries[num].granularity |= gran & 0xF0;
gGdtEntries[num].access = access;
}
void irqTimer();
static void initializeIdt()
{
gIdtPointer.limit = sizeof(IdtEntry) * 256 -1;
gIdtPointer.base = (uint32)&gIdtEntries;
memset((uint8*)&gIdtEntries, 0, sizeof(IdtEntry)*256);
// Remap the irq table.
outb(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x0);
outb(0xA1, 0x0);
setIdtEntry( 0, (uint32)isr0 , 0x08, 0x8E);
setIdtEntry( 1, (uint32)isr1 , 0x08, 0x8E);
setIdtEntry( 2, (uint32)isr2 , 0x08, 0x8E);
setIdtEntry( 3, (uint32)isr3 , 0x08, 0x8E);
setIdtEntry( 4, (uint32)isr4 , 0x08, 0x8E);
setIdtEntry( 5, (uint32)isr5 , 0x08, 0x8E);
setIdtEntry( 6, (uint32)isr6 , 0x08, 0x8E);
setIdtEntry( 7, (uint32)isr7 , 0x08, 0x8E);
setIdtEntry( 8, (uint32)isr8 , 0x08, 0x8E);
setIdtEntry( 9, (uint32)isr9 , 0x08, 0x8E);
setIdtEntry(10, (uint32)isr10, 0x08, 0x8E);
setIdtEntry(11, (uint32)isr11, 0x08, 0x8E);
setIdtEntry(12, (uint32)isr12, 0x08, 0x8E);
setIdtEntry(13, (uint32)isr13, 0x08, 0x8E);
setIdtEntry(14, (uint32)isr14, 0x08, 0x8E);
setIdtEntry(15, (uint32)isr15, 0x08, 0x8E);
setIdtEntry(16, (uint32)isr16, 0x08, 0x8E);
setIdtEntry(17, (uint32)isr17, 0x08, 0x8E);
setIdtEntry(18, (uint32)isr18, 0x08, 0x8E);
setIdtEntry(19, (uint32)isr19, 0x08, 0x8E);
setIdtEntry(20, (uint32)isr20, 0x08, 0x8E);
setIdtEntry(21, (uint32)isr21, 0x08, 0x8E);
setIdtEntry(22, (uint32)isr22, 0x08, 0x8E);
setIdtEntry(23, (uint32)isr23, 0x08, 0x8E);
setIdtEntry(24, (uint32)isr24, 0x08, 0x8E);
setIdtEntry(25, (uint32)isr25, 0x08, 0x8E);
setIdtEntry(26, (uint32)isr26, 0x08, 0x8E);
setIdtEntry(27, (uint32)isr27, 0x08, 0x8E);
setIdtEntry(28, (uint32)isr28, 0x08, 0x8E);
setIdtEntry(29, (uint32)isr29, 0x08, 0x8E);
setIdtEntry(30, (uint32)isr30, 0x08, 0x8E);
setIdtEntry(31, (uint32)isr31, 0x08, 0x8E);
setIdtEntry(32, (uint32)irqTimer, 0x08, 0x8E);
setIdtEntry(33, (uint32)irq1, 0x08, 0x8E);
setIdtEntry(34, (uint32)irq2, 0x08, 0x8E);
setIdtEntry(35, (uint32)irq3, 0x08, 0x8E);
setIdtEntry(36, (uint32)irq4, 0x08, 0x8E);
setIdtEntry(37, (uint32)irq5, 0x08, 0x8E);
setIdtEntry(38, (uint32)irq6, 0x08, 0x8E);
setIdtEntry(39, (uint32)irq7, 0x08, 0x8E);
setIdtEntry(40, (uint32)irq8, 0x08, 0x8E);
setIdtEntry(41, (uint32)irq9, 0x08, 0x8E);
setIdtEntry(42, (uint32)irq10, 0x08, 0x8E);
setIdtEntry(43, (uint32)irq11, 0x08, 0x8E);
setIdtEntry(44, (uint32)irq12, 0x08, 0x8E);
setIdtEntry(45, (uint32)irq13, 0x08, 0x8E);
setIdtEntry(46, (uint32)irq14, 0x08, 0x8E);
setIdtEntry(47, (uint32)irq15, 0x08, 0x8E);
setIdtEntry(128, (uint32)isr128, 0x08, 0x8E);
flushIdt((uint32)&gIdtPointer);
}
static void setIdtEntry(uint8 num, uint32 base, uint16 sel, uint8 flags)
{
gIdtEntries[num].base_lo = base & 0xFFFF;
gIdtEntries[num].base_hi = (base >> 16) & 0xFFFF;
gIdtEntries[num].sel = sel;
gIdtEntries[num].always0 = 0;
gIdtEntries[num].flags = flags | 0x60;
}
static void handleDoubleFault(Registers *regs)
{
printkf("Double fault!!! Error code:%d\n", regs->errorCode);
PANIC("Double fault!!!");
}
static void handleGeneralProtectionFault(Registers *regs)
{
printkf("General protection fault!!! Error code:%d - IP:%x\n", regs->errorCode, regs->eip);
Thread* faultingThread = getCurrentThread();
if (NULL != faultingThread)
{
Thread* mainThread = getMainKernelThread();
if (mainThread == faultingThread)
{
PANIC("General protection fault in Kernel main thread!!!");
}
else
{
printkf("Faulting thread is %d\n", faultingThread->threadId);
if (faultingThread->userMode)
{
printkf("Destroying process %d\n", faultingThread->owner->pid);
destroyProcess(faultingThread->owner);
}
else
{
printkf("Destroying kernel thread %d\n", faultingThread->threadId);
destroyThread(faultingThread);
}
waitForSchedule();
}
}
else
{
PANIC("General protection fault!!!");
}
}

View File

@ -0,0 +1,124 @@
#ifndef DESCRIPTORTABLES_H
#define DESCRIPTORTABLES_H
#include "common.h"
void initializeDescriptorTables();
struct GdtEntry
{
uint16 limit_low;
uint16 base_low;
uint8 base_middle;
uint8 access;
uint8 granularity;
uint8 base_high;
} __attribute__((packed));
typedef struct GdtEntry GdtEntry;
struct GdtPointer
{
uint16 limit;
uint32 base;
} __attribute__((packed));
typedef struct GdtPointer GdtPointer;
struct IdtEntry
{
uint16 base_lo;
uint16 sel;
uint8 always0;
uint8 flags;
uint16 base_hi;
} __attribute__((packed));
typedef struct IdtEntry IdtEntry;
struct IdtPointer
{
uint16 limit;
uint32 base;
} __attribute__((packed));
typedef struct IdtPointer IdtPointer;
struct Tss {
uint16 previous_task, __previous_task_unused;
uint32 esp0;
uint16 ss0, __ss0_unused;
uint32 esp1;
uint16 ss1, __ss1_unused;
uint32 esp2;
uint16 ss2, __ss2_unused;
uint32 cr3;
uint32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
uint16 es, __es_unused;
uint16 cs, __cs_unused;
uint16 ss, __ss_unused;
uint16 ds, __ds_unused;
uint16 fs, __fs_unused;
uint16 gs, __gs_unused;
uint16 ldt_selector, __ldt_sel_unused;
uint16 debug_flag, io_map;
} __attribute__ ((packed));
typedef struct Tss Tss;
extern void isr0 ();
extern void isr1 ();
extern void isr2 ();
extern void isr3 ();
extern void isr4 ();
extern void isr5 ();
extern void isr6 ();
extern void isr7 ();
extern void isr8 ();
extern void isr9 ();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();
extern void irq0 ();
extern void irq1 ();
extern void irq2 ();
extern void irq3 ();
extern void irq4 ();
extern void irq5 ();
extern void irq6 ();
extern void irq7 ();
extern void irq8 ();
extern void irq9 ();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();
extern void isr128();
#endif //DESCRIPTORTABLES_H

145
kernel.soso/devfs.c Normal file
View File

@ -0,0 +1,145 @@
#include "devfs.h"
#include "common.h"
#include "fs.h"
#include "alloc.h"
#include "device.h"
#include "screen.h"
#include "list.h"
#include "spinlock.h"
static FileSystemNode* gDevRoot = NULL;
static List* gDeviceList = NULL;
static Spinlock gDeviceListLock;
static BOOL devfs_open(File *node, uint32 flags);
static FileSystemDirent *devfs_readdir(FileSystemNode *node, uint32 index);
static FileSystemNode *devfs_finddir(FileSystemNode *node, char *name);
static FileSystemDirent gDirent;
void initializeDevFS()
{
gDevRoot = kmalloc(sizeof(FileSystemNode));
memset((uint8*)gDevRoot, 0, sizeof(FileSystemNode));
gDevRoot->nodeType = FT_Directory;
FileSystemNode* rootFs = getFileSystemRootNode();
FileSystemNode* devNode = finddir_fs(rootFs, "dev");
if (devNode)
{
devNode->nodeType |= FT_MountPoint;
devNode->mountPoint = gDevRoot;
gDevRoot->parent = devNode->parent;
strcpy(gDevRoot->name, devNode->name);
}
else
{
PANIC("/dev does not exist!");
}
gDevRoot->open = devfs_open;
gDevRoot->finddir = devfs_finddir;
gDevRoot->readdir = devfs_readdir;
gDeviceList = List_Create();
Spinlock_Init(&gDeviceListLock);
}
static BOOL devfs_open(File *node, uint32 flags)
{
return TRUE;
}
static FileSystemDirent *devfs_readdir(FileSystemNode *node, uint32 index)
{
FileSystemDirent * result = NULL;
uint32 counter = 0;
Spinlock_Lock(&gDeviceListLock);
List_Foreach(n, gDeviceList)
{
if (index == counter)
{
FileSystemNode* deviceNode = (FileSystemNode*)n->data;
strcpy(gDirent.name, deviceNode->name);
gDirent.fileType = deviceNode->nodeType;
gDirent.inode = index;
result = &gDirent;
break;
}
++counter;
}
Spinlock_Unlock(&gDeviceListLock);
return result;
}
static FileSystemNode *devfs_finddir(FileSystemNode *node, char *name)
{
FileSystemNode* result = NULL;
Spinlock_Lock(&gDeviceListLock);
List_Foreach(n, gDeviceList)
{
FileSystemNode* deviceNode = (FileSystemNode*)n->data;
if (strcmp(name, deviceNode->name) == 0)
{
result = deviceNode;
break;
}
}
Spinlock_Unlock(&gDeviceListLock);
return result;
}
FileSystemNode* registerDevice(Device* device)
{
Spinlock_Lock(&gDeviceListLock);
List_Foreach(n, gDeviceList)
{
FileSystemNode* deviceNode = (FileSystemNode*)n->data;
if (strcmp(device->name, deviceNode->name) == 0)
{
//There is already a device with the same name
Spinlock_Unlock(&gDeviceListLock);
return NULL;
}
}
FileSystemNode* deviceNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
memset((uint8*)deviceNode, 0, sizeof(FileSystemNode));
strcpy(deviceNode->name, device->name);
deviceNode->nodeType = device->deviceType;
deviceNode->open = device->open;
deviceNode->close = device->close;
deviceNode->readBlock = device->readBlock;
deviceNode->writeBlock = device->writeBlock;
deviceNode->read = device->read;
deviceNode->write = device->write;
deviceNode->ioctl = device->ioctl;
deviceNode->ftruncate = device->ftruncate;
deviceNode->mmap = device->mmap;
deviceNode->munmap = device->munmap;
deviceNode->privateNodeData = device->privateData;
deviceNode->parent = gDevRoot;
List_Append(gDeviceList, deviceNode);
Spinlock_Unlock(&gDeviceListLock);
return deviceNode;
}

11
kernel.soso/devfs.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef DEVFS_H
#define DEVFS_H
#include "device.h"
#include "fs.h"
#include "common.h"
void initializeDevFS();
FileSystemNode* registerDevice(Device* device);
#endif // DEVFS_H

24
kernel.soso/device.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef DEVICE_H
#define DEVICE_H
#include "common.h"
#include "fs.h"
typedef struct Device
{
char name[16];
FileType deviceType;
ReadWriteBlockFunction readBlock;
ReadWriteBlockFunction writeBlock;
ReadWriteFunction read;
ReadWriteFunction write;
OpenFunction open;
CloseFunction close;
IoctlFunction ioctl;
FtruncateFunction ftruncate;
MmapFunction mmap;
MunmapFunction munmap;
void * privateData;
} Device;
#endif // DEVICE_H

79
kernel.soso/elf.c Normal file
View File

@ -0,0 +1,79 @@
#include "elf.h"
#include "common.h"
#include "process.h"
#include "screen.h"
BOOL isElf(char *elfData)
{
Elf32_Ehdr *hdr = (Elf32_Ehdr *) elfData;
if (hdr->e_ident[0] == 0x7f && hdr->e_ident[1] == 'E' &&
hdr->e_ident[2] == 'L' && hdr->e_ident[3] == 'F')
{
return TRUE;
}
return FALSE;
}
uint32 loadElf(char *elfData)
{
uint32 v_begin, v_end;
Elf32_Ehdr *hdr;
Elf32_Phdr *p_entry;
Elf32_Scdr *s_entry;
hdr = (Elf32_Ehdr *) elfData;
p_entry = (Elf32_Phdr *) (elfData + hdr->e_phoff);
s_entry = (Elf32_Scdr*) (elfData + hdr->e_shoff);
if (isElf(elfData)==FALSE)
{
return 0;
}
for (int pe = 0; pe < hdr->e_phnum; pe++, p_entry++)
{
//Read each entry
printkf("loading p_entry %d\n", pe);
if (p_entry->p_type == PT_LOAD)
{
v_begin = p_entry->p_vaddr;
v_end = p_entry->p_vaddr + p_entry->p_memsz;
printkf("p_entry: %x\n", v_begin);
if (v_begin < USER_OFFSET)
{
printkf("INFO: loadElf(): can't load executable below %x\n", USER_OFFSET);
return 0;
}
if (v_end > USER_STACK)
{
printkf("INFO: loadElf(): can't load executable above %x\n", USER_STACK);
return 0;
}
//printkf("ELF: entry flags: %x (%d)\n", p_entry->p_flags, p_entry->p_flags);
printkf("about to memcpy\n");
memcpy((uint8 *) v_begin, (uint8 *) (elfData + p_entry->p_offset), p_entry->p_filesz);
printkf("done with memcpy\n");
if (p_entry->p_memsz > p_entry->p_filesz)
{
char* p = (char *) p_entry->p_vaddr;
for (int i = p_entry->p_filesz; i < (int)(p_entry->p_memsz); i++)
{
p[i] = 0;
}
}
}
}
//entry point
printkf("done loading ELF\n");
return hdr->e_entry;
}

184
kernel.soso/elf.h Normal file
View File

@ -0,0 +1,184 @@
#ifndef ELF_H
#define ELF_H
#include "common.h"
/*
* ELF HEADER
*/
typedef struct {
unsigned char e_ident[16]; /* ELF identification */
uint16 e_type; /* 2 (exec file) */
uint16 e_machine; /* 3 (intel architecture) */
uint32 e_version; /* 1 */
uint32 e_entry; /* starting point */
uint32 e_phoff; /* program header table offset */
uint32 e_shoff; /* section header table offset */
uint32 e_flags; /* various flags */
uint16 e_ehsize; /* ELF header (this) size */
uint16 e_phentsize; /* program header table entry size */
uint16 e_phnum; /* number of entries */
uint16 e_shentsize; /* section header table entry size */
uint16 e_shnum; /* number of entries */
uint16 e_shstrndx; /* index of the section name string table */
} Elf32_Ehdr;
/*
* ELF identification
*/
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
/* EI_MAG */
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
/* EI_CLASS */
#define ELFCLASSNONE 0 /* invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
/* EI_DATA */
#define ELFDATANONE 0 /* invalide data encoding */
#define ELFDATA2LSB 1 /* least significant byte first (0x01020304 is 0x04 0x03 0x02 0x01) */
#define ELFDATA2MSB 2 /* most significant byte first (0x01020304 is 0x01 0x02 0x03 0x04) */
/* EI_VERSION */
#define EV_CURRENT 1
#define ELFVERSION EV_CURRENT
/*
* PROGRAM HEADER
*/
typedef struct {
uint32 p_type; /* type of segment */
uint32 p_offset;
uint32 p_vaddr;
uint32 p_paddr;
uint32 p_filesz;
uint32 p_memsz;
uint32 p_flags;
uint32 p_align;
} Elf32_Phdr;
/* p_type */
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
/* p_flags */
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
enum eElfSectionTypes {
SHT_NULL, //0
SHT_PROGBITS, //1
SHT_SYMTAB, //2
SHT_STRTAB, //3
SHT_RELA, //4
SHT_HASH, //5
SHT_DYNAMIC, //6
SHT_NOTE, //7
SHT_NOBITS, //8
SHT_REL, //9
SHT_SHLIB, //A
SHT_DYNSYM, //B
SHT_LAST, //C
SHT_LOPROC = 0x70000000,
SHT_HIPROC = 0x7fffffff,
SHT_LOUSER = 0x80000000,
SHT_HIUSER = 0xffffffff
};
typedef struct {
uint32 name;
uint32 type;
uint32 flags;
uint32 address;
uint32 offset;
uint32 size;
uint32 link;
uint32 info;
uint32 addralign;
uint32 entsize;
} Elf32_Scdr;
enum {
R_386_NONE=0, // none
R_386_32, // S+A
R_386_PC32, // S+A-P
R_386_GOT32, // G+A-P
R_386_PLT32, // L+A-P
R_386_COPY, // none
R_386_GLOB_DAT, // S
R_386_JMP_SLOT, // S
R_386_RELATIVE, // B+A
R_386_GOTOFF, // S+A-GOT
R_386_GOTPC, // GOT+A-P
R_386_LAST // none
};
typedef struct {
uint16 d_tag;
uint32 d_val; //Also d_ptr
} Elf32_dyn;
enum {
DT_NULL, //!< Marks End of list
DT_NEEDED, //!< Offset in strtab to needed library
DT_PLTRELSZ, //!< Size in bytes of PLT
DT_PLTGOT, //!< Address of PLT/GOT
DT_HASH, //!< Address of symbol hash table
DT_STRTAB, //!< String Table address
DT_SYMTAB, //!< Symbol Table address
DT_RELA, //!< Relocation table address
DT_RELASZ, //!< Size of relocation table
DT_RELAENT, //!< Size of entry in relocation table
DT_STRSZ, //!< Size of string table
DT_SYMENT, //!< Size of symbol table entry
DT_INIT, //!< Address of initialisation function
DT_FINI, //!< Address of termination function
DT_SONAME, //!< String table offset of so name
DT_RPATH, //!< String table offset of library path
DT_SYMBOLIC,//!< Reverse order of symbol searching for library, search libs first then executable
DT_REL, //!< Relocation Entries (Elf32_Rel instead of Elf32_Rela)
DT_RELSZ, //!< Size of above table (bytes)
DT_RELENT, //!< Size of entry in above table
DT_PLTREL, //!< Relocation entry of PLT
DT_DEBUG, //!< Debugging Entry - Unknown contents
DT_TEXTREL, //!< Indicates that modifcations to a non-writeable segment may occur
DT_JMPREL, //!< Address of PLT only relocation entries
DT_LOPROC = 0x70000000, //!< Low Definable
DT_HIPROC = 0x7FFFFFFF //!< High Definable
};
BOOL isElf(char *elfData);
uint32 loadElf(char *elfData);
#endif // ELF_H

672
kernel.soso/fatfilesystem.c Normal file
View File

@ -0,0 +1,672 @@
#include "fatfilesystem.h"
#include "common.h"
#include "fs.h"
#include "alloc.h"
#include "fatfs_ff.h"
#include "fatfs_diskio.h"
#include "screen.h"
#define SEEK_SET 0 /* Seek from beginning of file. */
#define SEEK_CUR 1 /* Seek from current position. */
#define SEEK_END 2
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
static BOOL mount(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
static BOOL checkMount(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
static FileSystemDirent* readdir(FileSystemNode *node, uint32 index);
static FileSystemNode* finddir(FileSystemNode *node, char *name);
static int32 read(File *file, uint32 size, uint8 *buffer);
static int32 write(File *file, uint32 size, uint8 *buffer);
static int32 lseek(File *file, int32 offset, int32 whence);
static int32 stat(FileSystemNode *node, struct stat* buf);
static BOOL open(File *file, uint32 flags);
static void close(File *file);
static FileSystemDirent gFileSystemDirent;
static FileSystemNode* gMountedBlockDevices[FF_VOLUMES];
void initializeFatFileSystem()
{
FileSystem fs;
memset((uint8*)&fs, 0, sizeof(fs));
strcpy(fs.name, "fat");
fs.mount = mount;
fs.checkMount = checkMount;
registerFileSystem(&fs);
for (int i = 0; i < FF_VOLUMES; ++i)
{
gMountedBlockDevices[i] = NULL;
}
}
static BOOL mount(const char* sourcePath, const char* targetPath, uint32 flags, void *data)
{
printkf("fat mount source: %s\n", sourcePath);
FileSystemNode* node = getFileSystemNode(sourcePath);
if (node && node->nodeType == FT_BlockDevice)
{
FileSystemNode* targetNode = getFileSystemNode(targetPath);
if (targetNode)
{
if (targetNode->nodeType == FT_Directory)
{
printkf("fat mount target: %s\n", targetPath);
int32 volume = -1;
for (int32 v = 0; v < FF_VOLUMES; ++v)
{
if (NULL == gMountedBlockDevices[v])
{
volume = v;
break;
}
}
if (volume < 0)
{
return FALSE;
}
FileSystemNode* newNode = kmalloc(sizeof(FileSystemNode));
memset((uint8*)newNode, 0, sizeof(FileSystemNode));
strcpy(newNode->name, targetNode->name);
newNode->nodeType = FT_Directory;
newNode->open = open;
newNode->readdir = readdir;
newNode->finddir = finddir;
newNode->parent = targetNode->parent;
newNode->mountSource = node;
newNode->privateNodeData = (void*)volume;
gMountedBlockDevices[volume] = node;
FATFS* fatFs = (FATFS*)kmalloc(sizeof(FATFS));
//uint8 work[512];
//FRESULT fr = f_mkfs("", FM_FAT | FM_SFD, 512, work, 512);
//Screen_PrintF("f_mkfs: %d\n", fr);
char path[8];
sprintf(path, "%d:", volume);
FRESULT fr = f_mount(fatFs, path, 1);
//Screen_PrintF("f_mount: fr:%d drv:%d\n", fr, fatFs->pdrv);
if (FR_OK == fr)
{
targetNode->nodeType |= FT_MountPoint;
targetNode->mountPoint = newNode;
return TRUE;
}
else
{
kfree(newNode);
kfree(fatFs);
gMountedBlockDevices[volume] = NULL;
}
}
}
}
return FALSE;
}
static BOOL checkMount(const char* sourcePath, const char* targetPath, uint32 flags, void *data)
{
FileSystemNode* node = getFileSystemNode(sourcePath);
if (node && node->nodeType == FT_BlockDevice)
{
FileSystemNode* targetNode = getFileSystemNode(targetPath);
if (targetNode)
{
if (targetNode->nodeType == FT_Directory)
{
return TRUE;
}
}
}
return FALSE;
}
static FileSystemDirent* readdir(FileSystemNode *node, uint32 index)
{
//when node is the root of mounted filesystem,
//node->mountSource is the source node (eg. disk partition /dev/hd1p1)
//Screen_PrintF("readdir1: node->name:%s\n", node->name);
uint8 targetPath[128];
FileSystemNode *n = node;
int charIndex = 126;
memset(targetPath, 0, 128);
while (NULL == n->mountSource)
{
int length = strlen(n->name);
charIndex -= length;
if (charIndex < 2)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), n->name);
charIndex -= 1;
targetPath[charIndex] = '/';
n = n->parent;
}
char number[8];
sprintf(number, "%d", n->privateNodeData);//volume nuber
targetPath[charIndex] = ':';
int length = strlen(number);
charIndex -= length;
if (charIndex < 0)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), number);
uint8* target = targetPath + charIndex;
//Screen_PrintF("readdir: targetpath:[%s]\n", target);
DIR dir;
FRESULT fr = f_opendir(&dir, (TCHAR*)target);
if (FR_OK == fr)
{
FILINFO fileInfo;
for (int i = 0; i <= index; ++i)
{
memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
fr = f_readdir(&dir, &fileInfo);
if (strlen(fileInfo.fname) <= 0)
{
f_closedir(&dir);
return NULL;
}
}
gFileSystemDirent.inode = 0;
strcpy(gFileSystemDirent.name, fileInfo.fname);
if ((fileInfo.fattrib & AM_DIR) == AM_DIR)
{
gFileSystemDirent.fileType = FT_Directory;
}
else
{
gFileSystemDirent.fileType = FT_File;
}
f_closedir(&dir);
return &gFileSystemDirent;
}
return NULL;
}
static FileSystemNode* finddir(FileSystemNode *node, char *name)
{
//when node is the root of mounted filesystem,
//node->mountSource is the source node (eg. disk partition /dev/hd1p1)
//Screen_PrintF("finddir1: node->name:%s name:%s\n", node->name, name);
FileSystemNode* child = node->firstChild;
while (NULL != child)
{
if (strcmp(name, child->name) == 0)
{
return child;
}
child = child->nextSibling;
}
//If we are here, this file is accesed first time in this session.
//So we create its node...
uint8 targetPath[128];
FileSystemNode *n = node;
int charIndex = 126;
memset(targetPath, 0, 128);
int length = strlen(name);
charIndex -= length;
strcpyNonNull((char*)(targetPath + charIndex), name);
charIndex -= 1;
targetPath[charIndex] = '/';
while (NULL == n->mountSource)
{
length = strlen(n->name);
charIndex -= length;
if (charIndex < 2)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), n->name);
charIndex -= 1;
targetPath[charIndex] = '/';
n = n->parent;
}
char number[8];
sprintf(number, "%d", n->privateNodeData);//volume nuber
targetPath[charIndex] = ':';
length = strlen(number);
charIndex -= length;
if (charIndex < 0)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), number);
uint8* target = targetPath + charIndex;
//Screen_PrintF("finddir: targetpath:[%s]\n", target);
FILINFO fileInfo;
memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
FRESULT fr = f_stat((TCHAR*)target, &fileInfo);
if (FR_OK == fr)
{
FileSystemNode* newNode = kmalloc(sizeof(FileSystemNode));
memset((uint8*)newNode, 0, sizeof(FileSystemNode));
strcpy(newNode->name, name);
newNode->parent = node;
newNode->readdir = readdir;
newNode->finddir = finddir;
newNode->open = open;
newNode->close = close;
newNode->read = read;
newNode->write = write;
newNode->lseek = lseek;
newNode->stat = stat;
newNode->length = fileInfo.fsize;
if ((fileInfo.fattrib & AM_DIR) == AM_DIR)
{
newNode->nodeType = FT_Directory;
}
else
{
newNode->nodeType = FT_File;
}
if (NULL == node->firstChild)
{
node->firstChild = newNode;
}
else
{
FileSystemNode* child = node->firstChild;
while (NULL != child->nextSibling)
{
child = child->nextSibling;
}
child->nextSibling = newNode;
}
//Screen_PrintF("finddir: returning [%s]\n", name);
return newNode;
}
else
{
//Screen_PrintF("finddir error: fr: %d]\n", fr);
}
return NULL;
}
static int32 read(File *file, uint32 size, uint8 *buffer)
{
if (file->privateData == NULL)
{
return -1;
}
FIL* f = (FIL*)file->privateData;
UINT br = 0;
FRESULT fr = f_read(f, buffer, size, &br);
file->offset = f->fptr;
//Screen_PrintF("fat read: name:%s size:%d hasRead:%d, fr:%d\n", file->node->name, size, br, fr);
if (FR_OK == fr)
{
return br;
}
return -1;
}
static int32 write(File *file, uint32 size, uint8 *buffer)
{
if (file->privateData == NULL)
{
return -1;
}
FIL* f = (FIL*)file->privateData;
UINT bw = 0;
FRESULT fr = f_write(f, buffer, size, &bw);
file->offset = f->fptr;
if (FR_OK == fr)
{
return bw;
}
return -1;
}
static int32 lseek(File *file, int32 offset, int32 whence)
{
if (file->privateData == NULL)
{
return -1;
}
FIL* f = (FIL*)file->privateData;
FRESULT fr = FR_INVALID_OBJECT;
switch (whence)
{
case SEEK_SET:
fr = f_lseek(f, offset);
break;
case SEEK_CUR:
fr = f_lseek(f, f_tell(f) + offset);
break;
case SEEK_END:
fr = f_lseek(f, f_size(f) + offset);
break;
default:
break;
}
if (FR_OK == fr)
{
file->offset = f->fptr;
return file->offset;
}
return -1;
}
static int32 stat(FileSystemNode *node, struct stat* buf)
{
//Screen_PrintF("fat stat [%s]\n", node->name);
uint8 targetPath[128];
FileSystemNode *n = node;
int charIndex = 126;
memset(targetPath, 0, 128);
while (NULL == n->mountSource)
{
int length = strlen(n->name);
charIndex -= length;
if (charIndex < 2)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), n->name);
charIndex -= 1;
targetPath[charIndex] = '/';
n = n->parent;
}
char number[8];
sprintf(number, "%d", n->privateNodeData);//volume nuber
targetPath[charIndex] = ':';
int length = strlen(number);
charIndex -= length;
if (charIndex < 0)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), number);
uint8* target = targetPath + charIndex;
//Screen_PrintF("fat stat target:[%s]\n", target);
FILINFO fileInfo;
memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
FRESULT fr = f_stat((TCHAR*)target, &fileInfo);
if (FR_OK == fr)
{
if ((fileInfo.fattrib & AM_DIR) == AM_DIR)
{
node->nodeType = FT_Directory;
}
else
{
node->nodeType = FT_File;
}
node->length = fileInfo.fsize;
return 1;
}
return -1; //Error
}
static BOOL open(File *file, uint32 flags)
{
//Screen_PrintF("fat open %s\n", file->node->name);
FileSystemNode *node = file->node;
if (node->nodeType == FT_Directory)
{
return TRUE;
}
uint8 targetPath[128];
FileSystemNode *n = node;
int charIndex = 126;
memset(targetPath, 0, 128);
while (NULL == n->mountSource)
{
int length = strlen(n->name);
charIndex -= length;
if (charIndex < 2)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), n->name);
charIndex -= 1;
targetPath[charIndex] = '/';
n = n->parent;
}
char number[8];
sprintf(number, "%d", n->privateNodeData);//volume nuber
targetPath[charIndex] = ':';
int length = strlen(number);
charIndex -= length;
if (charIndex < 0)
{
return NULL;
}
strcpyNonNull((char*)(targetPath + charIndex), number);
uint8* target = targetPath + charIndex;
//Screen_PrintF("fat open %s\n", target);
int fatfsMode = FA_READ;
switch (flags)
{
case O_RDONLY:
fatfsMode = FA_READ;
break;
case O_WRONLY:
fatfsMode = FA_WRITE;
break;
case O_RDWR:
fatfsMode = (FA_READ | FA_WRITE);
break;
//TODO: append, create
default:
break;
}
FIL* f = (FIL*)kmalloc(sizeof(FIL));
FRESULT fr = f_open(f, (TCHAR*)target, fatfsMode);
if (FR_OK == fr)
{
file->offset = f->fptr;
file->privateData = f;
return TRUE;
}
return FALSE;
}
static void close(File *file)
{
if (file->privateData == NULL)
{
return;
}
FIL* f = (FIL*)file->privateData;
f_close(f);
kfree(f);
file->privateData = NULL;
}
DSTATUS disk_initialize(
BYTE pdrv //Physical drive nmuber
)
{
return 0;
}
DSTATUS disk_status(BYTE pdrv)
{
return 0;
}
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Number of sectors to read */
)
{
//Screen_PrintF("disk_read() drv:%d sector:%d count:%d\n", pdrv, sector, count);
if (gMountedBlockDevices[pdrv] == NULL) return RES_NOTRDY;
//if (sector >= RamDiskSize) return RES_PARERR;
gMountedBlockDevices[pdrv]->readBlock(gMountedBlockDevices[pdrv], (uint32)sector, count, buff);
return RES_OK;
}
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber (0) */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Number of sectors to write */
)
{
if (gMountedBlockDevices[pdrv] == NULL) return RES_NOTRDY;
//if (sector >= RamDiskSize) return RES_PARERR;
gMountedBlockDevices[pdrv]->writeBlock(gMountedBlockDevices[pdrv], (uint32)sector, count, (uint8*)buff);
return RES_OK;
}
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void* buff /* Buffer to send/receive data block */
)
{
if (gMountedBlockDevices[pdrv] == NULL) return RES_ERROR;
DRESULT dr = RES_ERROR;
File* f = NULL;
uint32 value = 0;
switch (ctrl)
{
case CTRL_SYNC:
dr = RES_OK;
break;
case GET_SECTOR_COUNT:
f = open_fs(gMountedBlockDevices[pdrv], 0);
if (f)
{
ioctl_fs(f, IC_GetSectorCount, &value);
*(DWORD*)buff = value;
dr = RES_OK;
close_fs(f);
}
printkf("disk_ioctl GET_SECTOR_COUNT: %d\n", value);
break;
case GET_BLOCK_SIZE:
f = open_fs(gMountedBlockDevices[pdrv], 0);
if (f)
{
ioctl_fs(f, IC_GetSectorSizeInBytes, &value);
*(DWORD*)buff = value;
dr = RES_OK;
close_fs(f);
}
printkf("disk_ioctl GET_BLOCK_SIZE: %d\n", value);
*(DWORD*)buff = value;
dr = RES_OK;
break;
}
return dr;
}

View File

@ -0,0 +1,6 @@
#ifndef FATFILESYSTEM_H
#define FATFILESYSTEM_H
void initializeFatFileSystem();
#endif // FATFILESYSTEM_H

View File

@ -0,0 +1,80 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#include "fatfs_integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

6555
kernel.soso/fatfs_ff.c Normal file

File diff suppressed because it is too large Load Diff

366
kernel.soso/fatfs_ff.h Normal file
View File

@ -0,0 +1,366 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13a /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2017, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/----------------------------------------------------------------------------*/
#ifndef FF_DEFINED
#define FF_DEFINED 89352 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "fatfs_integer.h" /* Basic integer types */
#include "fatfs_ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif
/* Type of path name strings on FatFs API */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
typedef char TCHAR;
#define _T(x) u8 ## x
#define _TEXT(x) u8 ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* Type of file size variables */
#if FF_FS_EXFAT
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:N/A) */
BYTE pdrv; /* Physical drive number */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */
#if FF_MAX_SS != FF_MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif
#if FF_USE_LFN
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */
#endif
#if FF_FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#if FF_FS_EXFAT
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* Object ID and allocation information (FFOBJID) */
typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
#endif
#if FF_FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} FFOBJID;
/* File object structure (FIL) */
typedef struct {
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !FF_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FFOBJID obj; /* Object identifier */
DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector (0:Read operation has terminated) */
BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if FF_USE_LFN
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif
#if FF_USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} DIR;
/* File information structure (FILINFO) */
typedef struct {
FSIZE_t fsize; /* File size */
WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */
#if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else
TCHAR fname[12 + 1]; /* File name */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void);
#endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
/* Sync functions */
#if FF_FS_REENTRANT
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA_OPEN_APPEND 0x30
/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
/* Format options (2nd argument of f_mkfs) */
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#ifdef __cplusplus
}
#endif
#endif /* FF_DEFINED */

283
kernel.soso/fatfs_ffconf.h Normal file
View File

@ -0,0 +1,283 @@
/*---------------------------------------------------------------------------/
/ FatFs - Configuration file
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 89352 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define FF_USE_MKFS 1
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_USE_FASTSEEK 0
/* This option switches fast seek function. (0:Disable or 1:Enable) */
#define FF_USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */
#define FF_USE_CHMOD 0
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define FF_USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define FF_USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE 932
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect code page setting can cause a file open failure.
/
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
/ 0 - Include all code pages above and configured by f_setcp()
*/
#define FF_USE_LFN 2
#define FF_MAX_LFN 255
/* The FF_USE_LFN switches the support for LFN (long file name).
/
/ 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
/ specification.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree() in ffsystem.c, need to be added to the project. */
#define FF_LFN_UNICODE 0
/* This option switches the character encoding on the API when LFN is enabled.
/
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 0
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
*/
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 10
/* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* FF_STR_VOLUME_ID switches string support for volume ID.
/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define FF_MULTI_PARTITION 0
/* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */
#define FF_MIN_SS 512
#define FF_MAX_SS 512
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
#define FF_USE_TRIM 0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 0
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ When enable exFAT, also LFN needs to be enabled.
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 1
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2017
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_LOCK 0
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/ is 1.
/
/ 0: Disable file lock function. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock function. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock control is independent of re-entrancy. */
#define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function.
/
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/

15586
kernel.soso/fatfs_ffunicode.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef FF_INTEGER
#define FF_INTEGER
#undef _WIN32
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
#include <tchar.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
typedef unsigned long long QWORD;
#endif
#endif

102
kernel.soso/fifobuffer.c Normal file
View File

@ -0,0 +1,102 @@
#include "fifobuffer.h"
#include "alloc.h"
FifoBuffer* FifoBuffer_create(uint32 capacity)
{
FifoBuffer* fifo = (FifoBuffer*)kmalloc(sizeof(FifoBuffer));
memset((uint8*)fifo, 0, sizeof(FifoBuffer));
fifo->data = (uint8*)kmalloc(capacity);
memset((uint8*)fifo->data, 0, capacity);
fifo->capacity= capacity;
return fifo;
}
void FifoBuffer_destroy(FifoBuffer* fifoBuffer)
{
kfree(fifoBuffer->data);
kfree(fifoBuffer);
}
void FifoBuffer_clear(FifoBuffer* fifoBuffer)
{
fifoBuffer->usedBytes = 0;
fifoBuffer->readIndex = 0;
fifoBuffer->writeIndex = 0;
}
BOOL FifoBuffer_isEmpty(FifoBuffer* fifoBuffer)
{
if (0 == fifoBuffer->usedBytes)
{
return TRUE;
}
return FALSE;
}
uint32 FifoBuffer_getSize(FifoBuffer* fifoBuffer)
{
return fifoBuffer->usedBytes;
}
uint32 FifoBuffer_getCapacity(FifoBuffer* fifoBuffer)
{
return fifoBuffer->capacity;
}
uint32 FifoBuffer_getFree(FifoBuffer* fifoBuffer)
{
return fifoBuffer->capacity - fifoBuffer->usedBytes;
}
int32 FifoBuffer_enqueue(FifoBuffer* fifoBuffer, uint8* data, uint32 size)
{
if (size == 0)
{
return -1;
}
uint32 bytesAvailable = fifoBuffer->capacity - fifoBuffer->usedBytes;
if (size > bytesAvailable)
{
return -1;
}
uint32 i = 0;
while (fifoBuffer->usedBytes < fifoBuffer->capacity && i < size)
{
fifoBuffer->data[fifoBuffer->writeIndex] = data[i++];
fifoBuffer->usedBytes++;
fifoBuffer->writeIndex++;
fifoBuffer->writeIndex %= fifoBuffer->capacity;
}
return size;
}
int32 FifoBuffer_dequeue(FifoBuffer* fifoBuffer, uint8* data, uint32 size)
{
if (size == 0)
{
return -1;
}
if (0 == fifoBuffer->usedBytes)
{
//Buffer is empty
return 0;
}
uint32 i = 0;
while (fifoBuffer->usedBytes > 0 && i < size)
{
data[i++] = fifoBuffer->data[fifoBuffer->readIndex];
fifoBuffer->usedBytes--;
fifoBuffer->readIndex++;
fifoBuffer->readIndex %= fifoBuffer->capacity;
}
return i;
}

25
kernel.soso/fifobuffer.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef FIFOBUFFER_H
#define FIFOBUFFER_H
#include "common.h"
typedef struct FifoBuffer
{
uint8* data;
uint32 writeIndex;
uint32 readIndex;
uint32 capacity;
uint32 usedBytes;
} FifoBuffer;
FifoBuffer* FifoBuffer_create(uint32 capacity);
void FifoBuffer_destroy(FifoBuffer* fifoBuffer);
void FifoBuffer_clear(FifoBuffer* fifoBuffer);
BOOL FifoBuffer_isEmpty(FifoBuffer* fifoBuffer);
uint32 FifoBuffer_getSize(FifoBuffer* fifoBuffer);
uint32 FifoBuffer_getCapacity(FifoBuffer* fifoBuffer);
uint32 FifoBuffer_getFree(FifoBuffer* fifoBuffer);
int32 FifoBuffer_enqueue(FifoBuffer* fifoBuffer, uint8* data, uint32 size);
int32 FifoBuffer_dequeue(FifoBuffer* fifoBuffer, uint8* data, uint32 size);
#endif // FIFOBUFFER_H

BIN
kernel.soso/font/font.o Normal file

Binary file not shown.

BIN
kernel.soso/font/font.psf Normal file

Binary file not shown.

108
kernel.soso/framebuffer.c Normal file
View File

@ -0,0 +1,108 @@
#include "devfs.h"
#include "device.h"
#include "common.h"
#include "gfx.h"
#include "framebuffer.h"
#include "vmm.h"
#include "process.h"
static BOOL fb_open(File *file, uint32 flags);
static int32 fb_read(File *file, uint32 size, uint8 *buffer);
static int32 fb_write(File *file, uint32 size, uint8 *buffer);
static int32 fb_ioctl(File *node, int32 request, void * argp);
static void* fb_mmap(File* file, uint32 size, uint32 offset, uint32 flags);
static BOOL fb_munmap(File* file, void* address, uint32 size);
static uint8* gFrameBufferPhysical = 0;
static uint8* gFrameBufferVirtual = 0;
void initializeFrameBuffer(uint8* p_address, uint8* v_address)
{
gFrameBufferPhysical = p_address;
gFrameBufferVirtual = v_address;
Device device;
memset((uint8*)&device, 0, sizeof(Device));
strcpy(device.name, "fb0");
device.deviceType = FT_CharacterDevice;
device.open = fb_open;
device.read = fb_read;
device.write = fb_write;
device.ioctl = fb_ioctl;
device.mmap = fb_mmap;
device.munmap = fb_munmap;
registerDevice(&device);
}
static BOOL fb_open(File *file, uint32 flags)
{
return TRUE;
}
static int32 fb_read(File *file, uint32 size, uint8 *buffer)
{
if (size == 0)
{
return 0;
}
return -1;
}
static int32 fb_write(File *file, uint32 size, uint8 *buffer)
{
if (size == 0)
{
return 0;
}
int32 requestedSize = size;
int32 length = Gfx_GetWidth() * Gfx_GetHeight() * 4;
int32 availableSize = length - file->offset;
if (availableSize <= 0)
{
return -1;
}
int32 targetSize = MIN(requestedSize, availableSize);
memcpy(gFrameBufferVirtual + file->offset, buffer, targetSize);
file->offset += targetSize;
return targetSize;
}
static int32 fb_ioctl(File *node, int32 request, void * argp)
{
int32 result = -1;
switch (request)
{
case FB_GET_WIDTH:
result = Gfx_GetWidth();
break;
case FB_GET_HEIGHT:
result = Gfx_GetHeight();
break;
case FB_GET_BITSPERPIXEL:
result = 32;
break;
}
return result;
}
static void* fb_mmap(File* file, uint32 size, uint32 offset, uint32 flags)
{
return mapMemory(file->thread->owner, size, (uint32)(gFrameBufferPhysical + offset), NULL);
}
static BOOL fb_munmap(File* file, void* address, uint32 size)
{
return unmapMemory(file->thread->owner, size, (uint32)address);
}

15
kernel.soso/framebuffer.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#include "common.h"
enum EnFrameBuferIoctl
{
FB_GET_WIDTH,
FB_GET_HEIGHT,
FB_GET_BITSPERPIXEL
};
void initializeFrameBuffer(uint8* p_address, uint8* v_address);
#endif // FRAMEBUFFER_H

634
kernel.soso/fs.c Normal file
View File

@ -0,0 +1,634 @@
#include "fs.h"
#include "alloc.h"
#include "screen.h"
#include "rootfs.h"
FileSystemNode *gFileSystemRoot = NULL; // The root of the filesystem.
#define FILESYSTEM_CAPACITY 10
static FileSystem gRegisteredFileSystems[FILESYSTEM_CAPACITY];
static int gNextFileSystemIndex = 0;
void initializeVFS()
{
memset((uint8*)gRegisteredFileSystems, 0, sizeof(gRegisteredFileSystems));
gFileSystemRoot = initializeRootFS();
mkdir_fs(gFileSystemRoot, "dev", 0);
mkdir_fs(gFileSystemRoot, "initrd", 0);
}
FileSystemNode* getFileSystemRootNode()
{
return gFileSystemRoot;
}
void copyFileDescriptors(Process* fromProcess, Process* toProcess)
{
for (int i = 0; i < MAX_OPENED_FILES; ++i)
{
File* original = fromProcess->fd[i];
if (original)
{
File* file = kmalloc(sizeof(File));
memcpy((uint8*)file, (uint8*)original, sizeof(File));
file->process = toProcess;
file->thread = NULL;
toProcess->fd[i] = file;
}
}
}
int getFileSystemNodePath(FileSystemNode *node, char* buffer, uint32 bufferSize)
{
if (node == gFileSystemRoot)
{
if (bufferSize > 1)
{
buffer[0] = '/';
buffer[1] = '\0';
return 1;
}
else
{
return -1;
}
}
char targetPath[128];
FileSystemNode *n = node;
int charIndex = 127;
targetPath[charIndex] = '\0';
while (NULL != n)
{
int length = strlen(n->name);
charIndex -= length;
if (charIndex < 2)
{
return -1;
}
if (NULL != n->parent)
{
strcpyNonNull(targetPath + charIndex, n->name);
charIndex -= 1;
targetPath[charIndex] = '/';
}
n = n->parent;
}
int len = 127 - charIndex;
//Screen_PrintF("getFileSystemNodePath: len:[%s] %d\n", targetPath + charIndex, len);
if (bufferSize < len)
{
return -1;
}
strcpy(buffer, targetPath + charIndex);
return len;
}
BOOL resolvePath(const char* path, char* buffer, int bufferSize)
{
int lengthPath = strlen(path);
if (path[0] != '/')
{
return FALSE;
}
if (bufferSize < 2)
{
return FALSE;
}
buffer[0] = '/';
buffer[1] = '\0';
int index = 0;
int indexBuffer = 1;
while (index < lengthPath - 1)
{
while (path[++index] == '/');//eliminate successive
const char* current = path + index;
int nextIndex = strFirstIndexOf(path + index, '/');
int lengthToken = 0;
if (nextIndex >= 0)
{
const char* next = path + index + nextIndex;
lengthToken = next - (path + index);
}
else
{
lengthToken = strlen(current);
}
if (lengthToken > 0)
{
index += lengthToken;
if (strncmp(current, "..", 2) == 0)
{
--indexBuffer;
while (indexBuffer > 0)
{
--indexBuffer;
if (buffer[indexBuffer] == '/')
{
break;
}
buffer[indexBuffer] = '\0';
}
++indexBuffer;
continue;
}
else if (strncmp(current, ".", 1) == 0)
{
continue;
}
if (indexBuffer + lengthToken + 2 > bufferSize)
{
return FALSE;
}
strncpy(buffer + indexBuffer, current, lengthToken);
indexBuffer += lengthToken;
if (current[lengthToken] == '/')
{
buffer[indexBuffer++] = '/';
}
buffer[indexBuffer] = '\0';
}
}
if (indexBuffer > 2)
{
if (buffer[indexBuffer - 1] == '/')
{
buffer[indexBuffer - 1] = '\0';
}
}
return TRUE;
}
uint32 read_fs(File *file, uint32 size, uint8 *buffer)
{
if (file->node->read != 0)
{
return file->node->read(file, size, buffer);
}
return -1;
}
uint32 write_fs(File *file, uint32 size, uint8 *buffer)
{
if (file->node->write != 0)
{
return file->node->write(file, size, buffer);
}
return -1;
}
File *open_fs(FileSystemNode *node, uint32 flags)
{
return open_fs_forProcess(getCurrentThread(), node, flags);
}
File *open_fs_forProcess(Thread* thread, FileSystemNode *node, uint32 flags)
{
Process* process = thread->owner;
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
{
node = node->mountPoint;
}
if (node->open != NULL)
{
File* file = kmalloc(sizeof(File));
memset((uint8*)file, 0, sizeof(File));
file->node = node;
file->process = process;
file->thread = thread;
BOOL success = node->open(file, flags);
if (success)
{
//Screen_PrintF("Opened:%s\n", file->node->name);
int32 fd = addFileToProcess(file->process, file);
if (fd < 0)
{
//TODO: sett errno max files opened already
printkf("Maxfiles opened already!!\n");
close_fs(file);
file = NULL;
}
}
else
{
kfree(file);
}
return file;
}
return NULL;
}
void close_fs(File *file)
{
if (file->node->close != NULL)
{
file->node->close(file);
}
removeFileFromProcess(file->process, file);
kfree(file);
}
int32 ioctl_fs(File *file, int32 request, void * argp)
{
if (file->node->ioctl != NULL)
{
return file->node->ioctl(file, request, argp);
}
return 0;
}
int32 lseek_fs(File *file, int32 offset, int32 whence)
{
if (file->node->lseek != NULL)
{
return file->node->lseek(file, offset, whence);
}
return 0;
}
int32 ftruncate_fs(File* file, int32 length)
{
if (file->node->ftruncate != NULL)
{
return file->node->ftruncate(file, length);
}
return -1;
}
int32 stat_fs(FileSystemNode *node, struct stat *buf)
{
#define __S_IFDIR 0040000 /* Directory. */
#define __S_IFCHR 0020000 /* Character device. */
#define __S_IFBLK 0060000 /* Block device. */
#define __S_IFREG 0100000 /* Regular file. */
#define __S_IFIFO 0010000 /* FIFO. */
#define __S_IFLNK 0120000 /* Symbolic link. */
#define __S_IFSOCK 0140000 /* Socket. */
if (node->stat != NULL)
{
int32 val = node->stat(node, buf);
if (val == 1)
{
//return value of 1 from driver means we should fill buf here.
if ((node->nodeType & FT_Directory) == FT_Directory)
{
buf->st_mode = __S_IFDIR;
}
else if ((node->nodeType & FT_CharacterDevice) == FT_CharacterDevice)
{
buf->st_mode = __S_IFCHR;
}
else if ((node->nodeType & FT_BlockDevice) == FT_BlockDevice)
{
buf->st_mode = __S_IFBLK;
}
else if ((node->nodeType & FT_Pipe) == FT_Pipe)
{
buf->st_mode = __S_IFIFO;
}
else if ((node->nodeType & FT_SymbolicLink) == FT_SymbolicLink)
{
buf->st_mode = __S_IFLNK;
}
else if ((node->nodeType & FT_File) == FT_File)
{
buf->st_mode = __S_IFREG;
}
buf->st_size = node->length;
return 0;
}
else
{
return val;
}
}
return -1;
}
FileSystemDirent *readdir_fs(FileSystemNode *node, uint32 index)
{
//Screen_PrintF("readdir_fs: node->name:%s index:%d\n", node->name, index);
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
{
if (NULL == node->mountPoint->readdir)
{
WARNING("mounted fs does not have readdir!\n");
}
else
{
return node->mountPoint->readdir(node->mountPoint, index);
}
}
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->readdir != NULL )
{
return node->readdir(node, index);
}
return NULL;
}
FileSystemNode *finddir_fs(FileSystemNode *node, char *name)
{
//Screen_PrintF("finddir_fs: name:%s\n", name);
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
{
if (NULL == node->mountPoint->finddir)
{
WARNING("mounted fs does not have finddir!\n");
}
else
{
return node->mountPoint->finddir(node->mountPoint, name);
}
}
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->finddir != NULL )
{
return node->finddir(node, name);
}
return NULL;
}
BOOL mkdir_fs(FileSystemNode *node, const char *name, uint32 flags)
{
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
{
if (node->mountPoint->mkdir)
{
return node->mountPoint->mkdir(node->mountPoint, name, flags);
}
}
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->mkdir != NULL )
{
return node->mkdir(node, name, flags);
}
return FALSE;
}
void* mmap_fs(File* file, uint32 size, uint32 offset, uint32 flags)
{
if (file->node->mmap)
{
return file->node->mmap(file, size, offset, flags);
}
return NULL;
}
BOOL munmap_fs(File* file, void* address, uint32 size)
{
if (file->node->munmap)
{
return file->node->munmap(file, address, size);
}
return FALSE;
}
FileSystemNode *getFileSystemNode(const char *path)
{
//Screen_PrintF("getFileSystemNode:%s *0\n", path);
if (path[0] != '/')
{
//We require absolute path!
return NULL;
}
char realPath[256];
BOOL resolved = resolvePath(path, realPath, 256);
if (FALSE == resolved)
{
return NULL;
}
const char* inputPath = realPath;
int pathLength = strlen(inputPath);
if (pathLength < 1)
{
return NULL;
}
//Screen_PrintF("getFileSystemNode:%s *1\n", path);
FileSystemNode* root = getFileSystemRootNode();
if (pathLength == 1)
{
return root;
}
int nextIndex = 0;
FileSystemNode* node = root;
//Screen_PrintF("getFileSystemNode:%s *2\n", path);
char buffer[64];
do
{
do_start:
inputPath = inputPath + nextIndex + 1;
nextIndex = strFirstIndexOf(inputPath, '/');
if (nextIndex == 0)
{
//detected successive slash
goto do_start;
}
if (nextIndex > 0)
{
int tokenSize = nextIndex;
strncpy(buffer, inputPath, tokenSize);
buffer[tokenSize] = '\0';
}
else
{
//Last part
strcpy(buffer, inputPath);
}
//Screen_PrintF("getFileSystemNode:%s *3\n", path);
node = finddir_fs(node, buffer);
//Screen_PrintF("getFileSystemNode:%s *4\n", path);
if (NULL == node)
{
return NULL;
}
} while (nextIndex > 0);
return node;
}
FileSystemNode* getFileSystemNodeAbsoluteOrRelative(const char* path, Process* process)
{
FileSystemNode* node = NULL;
if (process)
{
if ('\0' == path[0])
{
//empty
}
else if ('/' == path[0])
{
//absolute
node = getFileSystemNode(path);
}
else
{
//relative
if (process->workingDirectory)
{
char buffer[256];
if (getFileSystemNodePath(process->workingDirectory, buffer, 256) >= 0)
{
strcat(buffer, "/");
strcat(buffer, path);
//Screen_PrintF("getFileSystemNodeAbsoluteOrRelative:[%s]\n", buffer);
node = getFileSystemNode(buffer);
}
}
}
}
return node;
}
BOOL registerFileSystem(FileSystem* fs)
{
if (strlen(fs->name) <= 0)
{
return FALSE;
}
for (int i = 0; i < gNextFileSystemIndex; ++i)
{
if (strcmp(gRegisteredFileSystems[i].name, fs->name) == 0)
{
//name is in use
return FALSE;
}
}
gRegisteredFileSystems[gNextFileSystemIndex++] = *fs;
return TRUE;
}
BOOL mountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data)
{
FileSystem* fs = NULL;
for (int i = 0; i < gNextFileSystemIndex; ++i)
{
if (strcmp(gRegisteredFileSystems[i].name, fsType) == 0)
{
fs = &gRegisteredFileSystems[i];
break;
}
}
if (NULL == fs)
{
return FALSE;
}
return fs->mount(source, target, flags, data);
}
BOOL checkMountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data)
{
FileSystem* fs = NULL;
for (int i = 0; i < gNextFileSystemIndex; ++i)
{
if (strcmp(gRegisteredFileSystems[i].name, fsType) == 0)
{
fs = &gRegisteredFileSystems[i];
break;
}
}
if (NULL == fs)
{
return FALSE;
}
return fs->checkMount(source, target, flags, data);
}

155
kernel.soso/fs.h Normal file
View File

@ -0,0 +1,155 @@
#ifndef FS_H
#define FS_H
#include "common.h"
typedef enum FileType
{
FT_File = 1,
FT_CharacterDevice = 2,
FT_BlockDevice = 3,
FT_Pipe = 4,
FT_SymbolicLink = 5,
FT_Directory = 128,
FT_MountPoint = 256
} FileType;
typedef enum IoctlCommand
{
IC_GetSectorSizeInBytes,
IC_GetSectorCount,
} IoctlCommand;
typedef struct FileSystem FileSystem;
typedef struct FileSystemNode FileSystemNode;
typedef struct FileSystemDirent FileSystemDirent;
typedef struct Process Process;
typedef struct Thread Thread;
typedef struct File File;
struct stat;
typedef int32 (*ReadWriteFunction)(File* file, uint32 size, uint8* buffer);
typedef int32 (*ReadWriteBlockFunction)(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer);
typedef BOOL (*OpenFunction)(File* file, uint32 flags);
typedef void (*CloseFunction)(File* file);
typedef int32 (*IoctlFunction)(File *file, int32 request, void * argp);
typedef int32 (*LseekFunction)(File *file, int32 offset, int32 whence);
typedef int32 (*FtruncateFunction)(File *file, int32 length);
typedef int32 (*StatFunction)(FileSystemNode *node, struct stat *buf);
typedef FileSystemDirent * (*ReadDirFunction)(FileSystemNode*,uint32);
typedef FileSystemNode * (*FindDirFunction)(FileSystemNode*,char *name);
typedef BOOL (*MkDirFunction)(FileSystemNode* node, const char *name, uint32 flags);
typedef void* (*MmapFunction)(File* file, uint32 size, uint32 offset, uint32 flags);
typedef BOOL (*MunmapFunction)(File* file, void* address, uint32 size);
typedef BOOL (*MountFunction)(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
typedef struct FileSystem
{
char name[32];
MountFunction checkMount;
MountFunction mount;
} FileSystem;
typedef struct FileSystemNode
{
char name[128];
uint32 mask;
uint32 userId;
uint32 groupId;
uint32 nodeType;
uint32 inode;
uint32 length;
ReadWriteBlockFunction readBlock;
ReadWriteBlockFunction writeBlock;
ReadWriteFunction read;
ReadWriteFunction write;
OpenFunction open;
CloseFunction close;
IoctlFunction ioctl;
LseekFunction lseek;
FtruncateFunction ftruncate;
StatFunction stat;
ReadDirFunction readdir;
FindDirFunction finddir;
MkDirFunction mkdir;
MmapFunction mmap;
MunmapFunction munmap;
FileSystemNode *firstChild;
FileSystemNode *nextSibling;
FileSystemNode *parent;
FileSystemNode *mountPoint;//only used in mounts
FileSystemNode *mountSource;//only used in mounts
void* privateNodeData;
} FileSystemNode;
typedef struct FileSystemDirent
{
char name[128];
FileType fileType;
uint32 inode;
} FileSystemDirent;
//Per open
typedef struct File
{
FileSystemNode* node;
Process* process;
Thread* thread;
int32 fd;
int32 offset;
void* privateData;
} File;
struct stat
{
uint16/*dev_t */ st_dev; /* ID of device containing file */
uint16/*ino_t */ st_ino; /* inode number */
uint32/*mode_t */ st_mode; /* protection */
uint16/*nlink_t */ st_nlink; /* number of hard links */
uint16/*uid_t */ st_uid; /* user ID of owner */
uint16/*gid_t */ st_gid; /* group ID of owner */
uint16/*dev_t */ st_rdev; /* device ID (if special file) */
uint32/*off_t */ st_size; /* total size, in bytes */
uint32/*time_t */ st_atime;
uint32/*long */ st_spare1;
uint32/*time_t */ st_mtime;
uint32/*long */ st_spare2;
uint32/*time_t */ st_ctime;
uint32/*long */ st_spare3;
uint32/*blksize_t */ st_blksize;
uint32/*blkcnt_t */ st_blocks;
uint32/*long */ st_spare4[2];
};
uint32 read_fs(File* file, uint32 size, uint8* buffer);
uint32 write_fs(File* file, uint32 size, uint8* buffer);
File* open_fs(FileSystemNode* node, uint32 flags);
File* open_fs_forProcess(Thread* thread, FileSystemNode* node, uint32 flags);
void close_fs(File* file);
int32 ioctl_fs(File* file, int32 request, void* argp);
int32 lseek_fs(File* file, int32 offset, int32 whence);
int32 ftruncate_fs(File* file, int32 length);
int32 stat_fs(FileSystemNode *node, struct stat *buf);
FileSystemDirent* readdir_fs(FileSystemNode* node, uint32 index);
FileSystemNode* finddir_fs(FileSystemNode* node, char* name);
BOOL mkdir_fs(FileSystemNode *node, const char* name, uint32 flags);
void* mmap_fs(File* file, uint32 size, uint32 offset, uint32 flags);
BOOL munmap_fs(File* file, void* address, uint32 size);
int getFileSystemNodePath(FileSystemNode* node, char* buffer, uint32 bufferSize);
BOOL resolvePath(const char* path, char* buffer, int bufferSize);
void initializeVFS();
FileSystemNode* getFileSystemRootNode();
FileSystemNode* getFileSystemNode(const char* path);
FileSystemNode* getFileSystemNodeAbsoluteOrRelative(const char* path, Process* process);
void copyFileDescriptors(Process* fromProcess, Process* toProcess);
BOOL registerFileSystem(FileSystem* fs);
BOOL mountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data);
BOOL checkMountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data);
#endif

30
kernel.soso/gdt.asm Normal file
View File

@ -0,0 +1,30 @@
[GLOBAL flushGdt]
flushGdt:
mov eax, [esp+4] ;[esp+4] is the parametered passed
lgdt [eax]
mov ax, 0x10 ;0x10 is the offset to our data segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ;0x08 is the offset to our code segment
.flush:
ret
[GLOBAL flushIdt]
flushIdt:
mov eax, [esp+4] ;[esp+4] is the parametered passed
lidt [eax]
ret
[GLOBAL flushTss]
flushTss:
mov ax, 0x2B ;index of the TSS structure is 0x28 (5*8) and OR'ing two bits in order to set RPL 3 and we get 0x2B
ltr ax
ret

178
kernel.soso/gfx.c Normal file
View File

@ -0,0 +1,178 @@
#include "gfx.h"
#include "vmm.h"
#include "serial.h"
#include "framebuffer.h"
#include "debugprint.h"
static uint32 gWidth = 0;
static uint32 gHeight = 0;
static uint32 gBytesPerPixel = 0;
static uint32 gPitch = 0;
static uint32* gPixels = NULL;
extern char _binary_font_psf_start;
extern char _binary_font_psf_end;
uint16 *gUnicode = NULL;
static int gLineCount = 10;
static int gColumnCount = 10;
static uint16 gCurrentLine = 0;
static uint16 gCurrentColumn = 0;
#define LINE_HEIGHT 16
void Gfx_Initialize(uint32* pixels, uint32 width, uint32 height, uint32 bytesPerPixel, uint32 pitch)
{
char* p_address = (char*)pixels;
char* v_address = (char*)GFX_MEMORY;
//Usually physical and virtual are the same here but of course they don't have to
gPixels = (uint32*)v_address;
gWidth = width;
gHeight = height;
gBytesPerPixel = bytesPerPixel;
gPitch = pitch;
gLineCount = gHeight / LINE_HEIGHT;
gColumnCount = gWidth / 8;
BOOL success = addPageToPd(gKernelPageDirectory, v_address, p_address, 0);
if (success)
{
for (int y = 0; y < gHeight; ++y)
{
for (int x = 0; x < gWidth; ++x)
{
gPixels[x + y * gWidth] = 0xFFFFFFFF;
}
}
}
else
{
Debug_PrintF("Gfx initialization failed!\n");
}
initializeFrameBuffer((uint8*)p_address, (uint8*)v_address);
}
#define PSF_FONT_MAGIC 0x864ab572
typedef struct {
uint32 magic; /* magic bytes to identify PSF */
uint32 version; /* zero */
uint32 headersize; /* offset of bitmaps in file, 32 */
uint32 flags; /* 0 if there's no unicode table */
uint32 numglyph; /* number of glyphs */
uint32 bytesperglyph; /* size of each glyph */
uint32 height; /* height in pixels */
uint32 width; /* width in pixels */
} PSF_font;
//From Osdev PC Screen Font (The font used here is free to use)
void Gfx_PutCharAt(
/* note that this is int, not char as it's a unicode character */
unsigned short int c,
/* cursor position on screen, in characters not in pixels */
int cx, int cy,
/* foreground and background colors, say 0xFFFFFF and 0x000000 */
uint32 fg, uint32 bg)
{
/* cast the address to PSF header struct */
PSF_font *font = (PSF_font*)&_binary_font_psf_start;
/* we need to know how many bytes encode one row */
int bytesperline=(font->width+7)/8;
/* unicode translation */
if(gUnicode != NULL) {
c = gUnicode[c];
}
/* get the glyph for the character. If there's no
glyph for a given character, we'll display the first glyph. */
unsigned char *glyph =
(unsigned char*)&_binary_font_psf_start +
font->headersize +
(c>0&&c<font->numglyph?c:0)*font->bytesperglyph;
/* calculate the upper left corner on screen where we want to display.
we only do this once, and adjust the offset later. This is faster. */
int offs =
(cy * font->height * gPitch) +
(cx * (font->width+1) * 4);
/* finally display pixels according to the bitmap */
int x,y, line,mask;
for(y=0;y<font->height;y++){
/* save the starting position of the line */
line=offs;
mask=1<<(font->width-1);
/* display a row */
for(x=0;x<font->width;x++)
{
if (c == 0)
{
*((uint32*)((uint8*)gPixels + line)) = bg;
}
else
{
*((uint32*)((uint8*)gPixels + line)) = ((int)*glyph) & (mask) ? fg : bg;
}
/* adjust to the next pixel */
mask >>= 1;
line += 4;
}
/* adjust to the next line */
glyph += bytesperline;
offs += gPitch;
}
}
void Gfx_FlushFromTty(Tty* tty)
{
for (uint32 r = 0; r < tty->lineCount; ++r)
{
for (uint32 c = 0; c < tty->columnCount; ++c)
{
uint8* ttyPos = tty->buffer + (r * tty->columnCount + c) * 2;
uint8 chr = ttyPos[0];
uint8 color = ttyPos[1];
Gfx_PutCharAt(chr, c, r, 0, 0xFFFFFFFF);
}
}
//Screen_MoveCursor(tty->currentLine, tty->currentColumn);
}
uint8* Gfx_GetVideoMemory()
{
return (uint8*)gPixels;
}
uint16 Gfx_GetWidth()
{
return gWidth;
}
uint16 Gfx_GetHeight()
{
return gHeight;
}
uint16 Gfx_GetBytesPerPixel()
{
return gBytesPerPixel;
}
void Gfx_Fill(uint32 color)
{
for (uint32 y = 0; y < gHeight; ++y)
{
for (uint32 x = 0; x < gWidth; ++x)
{
gPixels[x + y * gWidth] = color;
}
}
}

25
kernel.soso/gfx.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef GFX_H
#define GFX_H
#include "common.h"
#include "tty.h"
void Gfx_Initialize(uint32* pixels, uint32 width, uint32 height, uint32 bytesPerPixel, uint32 pitch);
void Gfx_PutCharAt(
/* note that this is int, not char as it's a unicode character */
unsigned short int c,
/* cursor position on screen, in characters not in pixels */
int cx, int cy,
/* foreground and background colors, say 0xFFFFFF and 0x000000 */
uint32 fg, uint32 bg);
void Gfx_FlushFromTty(Tty* tty);
uint8* Gfx_GetVideoMemory();
uint16 Gfx_GetWidth();
uint16 Gfx_GetHeight();
uint16 Gfx_GetBytesPerPixel();
void Gfx_Fill(uint32 color);
#endif // GFX_H

18
kernel.soso/grub.cfg Normal file
View File

@ -0,0 +1,18 @@
insmod vbe
insmod vga
menuentry "SOSO DISK" {
set root=(hd0,1)
multiboot /boot/kernel.bin
module /boot/initrd.fat
set gfxpayload=1024x768x32
boot
}
menuentry "SOSO CD" {
set root=(cd)
multiboot /boot/kernel.bin
module /boot/initrd.fat
set gfxpayload=1024x768x32
boot
}

132
kernel.soso/hashtable.c Normal file
View File

@ -0,0 +1,132 @@
#include "hashtable.h"
#include "alloc.h"
typedef struct DataItem
{
uint32 data;
uint32 key;
uint8 used;
} DataItem;
typedef struct HashTable
{
DataItem* items;
uint32 capacity;
} HashTable;
static uint32 hashCode(HashTable* hashTable, uint32 key)
{
return key % hashTable->capacity;
}
HashTable* HashTable_create(uint32 capacity)
{
HashTable* hashTable = kmalloc(sizeof(HashTable));
memset((uint8*)hashTable, 0, sizeof(HashTable));
hashTable->capacity = capacity;
hashTable->items = kmalloc(sizeof(DataItem) * capacity);
return hashTable;
}
void HashTable_destroy(HashTable* hashTable)
{
kfree(hashTable->items);
kfree(hashTable);
}
DataItem* HashTable_search_internal(HashTable* hashTable, uint32 key)
{
//get the hash
uint32 hashIndex = hashCode(hashTable, key);
uint32 counter = 0;
while(counter < hashTable->capacity)
{
if(hashTable->items[hashIndex].key == key)
{
if(hashTable->items[hashIndex].used == TRUE)
{
return &(hashTable->items[hashIndex]);
}
}
//go to next cell
++hashIndex;
//wrap around the table
hashIndex %= hashTable->capacity;
++counter;
}
return NULL;
}
BOOL HashTable_search(HashTable* hashTable, uint32 key, uint32* value)
{
DataItem* existing = HashTable_search_internal(hashTable, key);
if (existing)
{
*value = existing->data;
return TRUE;
}
return FALSE;
}
BOOL HashTable_insert(HashTable* hashTable, uint32 key, uint32 data)
{
DataItem* existing = HashTable_search_internal(hashTable, key);
if (existing)
{
existing->data = data;
return TRUE;
}
//get the hash
uint32 hashIndex = hashCode(hashTable, key);
uint32 counter = 0;
//move in array until an empty or deleted cell
while(counter < hashTable->capacity)
{
if (hashTable->items[hashIndex].used == FALSE)
{
hashTable->items[hashIndex].key = key;
hashTable->items[hashIndex].data = data;
hashTable->items[hashIndex].used = TRUE;
return TRUE;
}
//go to next cell
++hashIndex;
//wrap around the table
hashIndex %= hashTable->capacity;
++counter;
}
return FALSE;
}
BOOL HashTable_remove(HashTable* hashTable, uint32 key)
{
DataItem* existing = HashTable_search_internal(hashTable, key);
if (existing)
{
existing->used = FALSE;
return TRUE;
}
return FALSE;
}

14
kernel.soso/hashtable.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include "common.h"
typedef struct HashTable HashTable;
HashTable* HashTable_create(uint32 capacity);
void HashTable_destroy(HashTable* hashTable);
BOOL HashTable_search(HashTable* hashTable, uint32 key, uint32* value);
BOOL HashTable_insert(HashTable* hashTable, uint32 key, uint32 data);
BOOL HashTable_remove(HashTable* hashTable, uint32 key);
#endif // HASHTABLE_H

133
kernel.soso/interrupt.asm Normal file
View File

@ -0,0 +1,133 @@
; NASM macro
%macro ISR_ERROR_CODE 1
global isr%1
isr%1:
push dword %1 ; push the interrupt number
jmp handleISRCommon
%endmacro
; NASM macro
%macro ISR_NO_ERROR_CODE 1
global isr%1
isr%1:
push dword 0 ; push a dummy error code just because to keep struct Registers the same as the above macro
push dword %1 ; push the interrupt number
jmp handleISRCommon
%endmacro
; NASM macro
%macro IRQ 2
global irq%1
irq%1:
push dword 0 ; push a dummy error code just because to keep struct Registers the same again
push dword %2
jmp handleIRQCommon
%endmacro
ISR_NO_ERROR_CODE 0
ISR_NO_ERROR_CODE 1
ISR_NO_ERROR_CODE 2
ISR_NO_ERROR_CODE 3
ISR_NO_ERROR_CODE 4
ISR_NO_ERROR_CODE 5
ISR_NO_ERROR_CODE 6
ISR_NO_ERROR_CODE 7
ISR_ERROR_CODE 8
ISR_NO_ERROR_CODE 9
ISR_ERROR_CODE 10
ISR_ERROR_CODE 11
ISR_ERROR_CODE 12
ISR_ERROR_CODE 13
ISR_ERROR_CODE 14
ISR_NO_ERROR_CODE 15
ISR_NO_ERROR_CODE 16
ISR_NO_ERROR_CODE 17
ISR_NO_ERROR_CODE 18
ISR_NO_ERROR_CODE 19
ISR_NO_ERROR_CODE 20
ISR_NO_ERROR_CODE 21
ISR_NO_ERROR_CODE 22
ISR_NO_ERROR_CODE 23
ISR_NO_ERROR_CODE 24
ISR_NO_ERROR_CODE 25
ISR_NO_ERROR_CODE 26
ISR_NO_ERROR_CODE 27
ISR_NO_ERROR_CODE 28
ISR_NO_ERROR_CODE 29
ISR_NO_ERROR_CODE 30
ISR_NO_ERROR_CODE 31
ISR_NO_ERROR_CODE 128
; IRQ0 is handled by irqTimer below
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47
%macro SAVE_REGS 0
pushad
push ds ;those registers are 16 bit but they are pushed as 32 bits here
push es
push fs
push gs
push ebx
mov bx, 0x10 ; load the kernel data segment descriptor
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
pop ebx
%endmacro
%macro RESTORE_REGS 0
pop gs
pop fs
pop es
pop ds
popad
%endmacro
extern handleISR
handleISRCommon:
SAVE_REGS
call handleISR
RESTORE_REGS
add esp, 8 ; deallocate the error code and the interrupt number
iret ; pops CS, EIP, EFLAGS and also SS, and ESP if privilege change occurs
extern handleIRQ
handleIRQCommon:
SAVE_REGS
call handleIRQ
RESTORE_REGS
add esp, 8 ; deallocate the error code and the interrupt number
iret ; pops CS, EIP, EFLAGS and also SS, and ESP if privilege change occurs
extern handleTimerIRQ
global irqTimer
irqTimer: ; this does not have int no and error code in the stack, so there is no "add esp, 8"
SAVE_REGS
call handleTimerIRQ
mov al,0x20
out 0x20,al
RESTORE_REGS
iret

51
kernel.soso/isr.c Normal file
View File

@ -0,0 +1,51 @@
#include "common.h"
#include "isr.h"
#include "screen.h"
IsrFunction gInterruptHandlers[256];
extern uint32 gSystemTickCount;
void registerInterruptHandler(uint8 n, IsrFunction handler)
{
gInterruptHandlers[n] = handler;
}
void handleISR(Registers regs)
{
//Screen_PrintF("handleISR interrupt no:%d\n", regs.int_no);
uint8 int_no = regs.interruptNumber & 0xFF;
if (gInterruptHandlers[int_no] != 0)
{
IsrFunction handler = gInterruptHandlers[int_no];
handler(&regs);
}
else
{
printkf("unhandled interrupt: %d\n", int_no);
printkf("Tick: %d\n", gSystemTickCount);
PANIC("unhandled interrupt");
}
}
void handleIRQ(Registers regs)
{
// end of interrupt message
if (regs.interruptNumber >= 40)
{
//slave PIC
outb(0xA0, 0x20);
}
outb(0x20, 0x20);
//Screen_PrintF("irq: %d\n", regs.int_no);
if (gInterruptHandlers[regs.interruptNumber] != 0)
{
IsrFunction handler = gInterruptHandlers[regs.interruptNumber];
handler(&regs);
}
}

37
kernel.soso/isr.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef ISR_H
#define ISR_H
#include "common.h"
#define IRQ0 32
#define IRQ1 33
#define IRQ2 34
#define IRQ3 35
#define IRQ4 36
#define IRQ5 37
#define IRQ6 38
#define IRQ7 39
#define IRQ8 40
#define IRQ9 41
#define IRQ10 42
#define IRQ11 43
#define IRQ12 44
#define IRQ13 45
#define IRQ14 46
#define IRQ15 47
typedef struct Registers
{
uint32 gs;
uint32 fs;
uint32 es;
uint32 ds;
uint32 edi, esi, ebp, esp, ebx, edx, ecx, eax; //pushed by pusha
uint32 interruptNumber, errorCode; //if applicable
uint32 eip, cs, eflags, userEsp, ss; //pushed by the CPU
} Registers;
typedef void (*IsrFunction)(Registers*);
void registerInterruptHandler(uint8 n, IsrFunction handler);
#endif //ISR_H

184
kernel.soso/keyboard.c Normal file
View File

@ -0,0 +1,184 @@
#include "keyboard.h"
#include "isr.h"
#include "common.h"
#include "screen.h"
#include "ttydriver.h"
#include "fs.h"
#include "device.h"
#include "alloc.h"
#include "devfs.h"
#include "list.h"
static uint8* gKeyBuffer = NULL;
static uint32 gKeyBufferWriteIndex = 0;
static uint32 gKeyBufferReadIndex = 0;
#define KEYBUFFER_SIZE 128
static BOOL keyboard_open(File *file, uint32 flags);
static void keyboard_close(File *file);
static int32 keyboard_read(File *file, uint32 size, uint8 *buffer);
static int32 keyboard_ioctl(File *file, int32 request, void * argp);
typedef enum ReadMode
{
Blocking = 0,
NonBlocking = 1
} ReadMode;
typedef struct Reader
{
uint32 readIndex;
ReadMode readMode;
} Reader;
static List* gReaders = NULL;
static void handleKeyboardInterrupt(Registers *regs);
void initializeKeyboard()
{
Device device;
memset((uint8*)&device, 0, sizeof(Device));
strcpy(device.name, "keyboard");
device.deviceType = FT_CharacterDevice;
device.open = keyboard_open;
device.close = keyboard_close;
device.read = keyboard_read;
device.ioctl = keyboard_ioctl;
gKeyBuffer = kmalloc(KEYBUFFER_SIZE);
memset((uint8*)gKeyBuffer, 0, KEYBUFFER_SIZE);
gReaders = List_Create();
registerDevice(&device);
registerInterruptHandler(IRQ1, handleKeyboardInterrupt);
}
static BOOL keyboard_open(File *file, uint32 flags)
{
Reader* reader = (Reader*)kmalloc(sizeof(Reader));
reader->readIndex = 0;
reader->readMode = Blocking;
if (gKeyBufferWriteIndex > 0)
{
reader->readIndex = gKeyBufferWriteIndex;
}
file->privateData = (void*)reader;
List_Append(gReaders, file);
return TRUE;
}
static void keyboard_close(File *file)
{
//Screen_PrintF("keyboard_close\n");
Reader* reader = (Reader*)file->privateData;
kfree(reader);
List_RemoveFirstOccurrence(gReaders, file);
}
static int32 keyboard_read(File *file, uint32 size, uint8 *buffer)
{
Reader* reader = (Reader*)file->privateData;
uint32 readIndex = reader->readIndex;
if (reader->readMode == Blocking)
{
while (readIndex == gKeyBufferWriteIndex)
{
file->thread->state = TS_WAITIO;
file->thread->state_privateData = keyboard_read;
enableInterrupts();
halt();
}
}
disableInterrupts();
if (readIndex == gKeyBufferWriteIndex)
{
//non-blocking return here
return -1;
}
buffer[0] = gKeyBuffer[readIndex];
readIndex++;
readIndex %= KEYBUFFER_SIZE;
reader->readIndex = readIndex;
return 1;
}
static int32 keyboard_ioctl(File *file, int32 request, void * argp)
{
Reader* reader = (Reader*)file->privateData;
int cmd = (int)argp;
switch (request)
{
case 0: //get
*(int*)argp = (int)reader->readMode;
return 0;
break;
case 1: //set
if (cmd == 0)
{
reader->readMode = Blocking;
return 0;
}
else if (cmd == 1)
{
reader->readMode = NonBlocking;
return 0;
}
break;
default:
break;
}
return -1;
}
static void handleKeyboardInterrupt(Registers *regs)
{
uint8 scancode = 0;
do
{
scancode = inb(0x64);
} while ((scancode & 0x01) == 0);
scancode = inb(0x60);
gKeyBuffer[gKeyBufferWriteIndex] = scancode;
gKeyBufferWriteIndex++;
gKeyBufferWriteIndex %= KEYBUFFER_SIZE;
//Wake readers
List_Foreach(n, gReaders)
{
File* file = n->data;
if (file->thread->state == TS_WAITIO)
{
if (file->thread->state_privateData == keyboard_read)
{
file->thread->state = TS_RUN;
file->thread->state_privateData = NULL;
}
}
}
sendKeyInputToTTY(getActiveTTY(), scancode);
}

6
kernel.soso/keyboard.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef KEYBOARD_H
#define KEYBOARD_H
void initializeKeyboard();
#endif // KEYBOARD_H

34
kernel.soso/link.ld Normal file
View File

@ -0,0 +1,34 @@
ENTRY(_start)
SECTIONS
{
. = 1M;
/* Code. */
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
/* Read-only data. */
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata)
}
/* Read-write data (initialized) */
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
/* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
_end = .;
}

304
kernel.soso/list.c Normal file
View File

@ -0,0 +1,304 @@
#include "alloc.h"
#include "common.h"
#include "list.h"
List* List_Create()
{
List* list = (List*)kmalloc(sizeof(List));
memset((uint8*)list, 0, sizeof(List));
return list;
}
void List_Clear(List* list)
{
ListNode* listNode = list->head;
while (NULL != listNode)
{
ListNode* next = listNode->next;
kfree(listNode);
listNode = next;
}
list->head = NULL;
list->tail = NULL;
}
void List_Destroy(List* list)
{
List_Clear(list);
kfree(list);
}
List* List_CreateClone(List* list)
{
List* newList = List_Create();
List_Foreach(n, list)
{
List_Append(newList, n->data);
}
return newList;
}
BOOL List_IsEmpty(List* list)
{
//At empty state, both head and tail are null!
return list->head == NULL;
}
void List_Append(List* list, void* data)
{
ListNode* node = (ListNode*)kmalloc(sizeof(ListNode));
memset((uint8*)node, 0, sizeof(ListNode));
node->data = data;
//At empty state, both head and tail are null!
if (NULL == list->tail)
{
list->head = node;
list->tail = node;
return;
}
node->previous = list->tail;
node->previous->next = node;
list->tail = node;
}
void List_Prepend(List* list, void* data)
{
ListNode* node = (ListNode*)kmalloc(sizeof(ListNode));
memset((uint8*)node, 0, sizeof(ListNode));
node->data = data;
//At empty state, both head and tail are null!
if (NULL == list->tail)
{
list->head = node;
list->tail = node;
return;
}
node->next = list->head;
node->next->previous = node;
list->head = node;
}
ListNode* List_GetFirstNode(List* list)
{
return list->head;
}
ListNode* List_GetLastNode(List* list)
{
return list->tail;
}
ListNode* List_FindFirstOccurrence(List* list, void* data)
{
List_Foreach(n, list)
{
if (n->data == data)
{
return n;
}
}
return NULL;
}
int List_FindFirstOccurrenceIndex(List* list, void* data)
{
int result = 0;
List_Foreach(n, list)
{
if (n->data == data)
{
return result;
}
++result;
}
return -1;
}
int List_GetCount(List* list)
{
int result = 0;
List_Foreach(n, list)
{
++result;
}
return result;
}
void List_RemoveNode(List* list, ListNode* node)
{
if (NULL == node)
{
return;
}
if (NULL != node->previous)
{
node->previous->next = node->next;
}
if (NULL != node->next)
{
node->next->previous = node->previous;
}
if (node == list->head)
{
list->head = node->next;
}
if (node == list->tail)
{
list->tail = node->previous;
}
kfree(node);
}
void List_RemoveFirstNode(List* list)
{
if (NULL != list->head)
{
List_RemoveNode(list, list->head);
}
}
void List_RemoveLastNode(List* list)
{
if (NULL != list->tail)
{
List_RemoveNode(list, list->tail);
}
}
void List_RemoveFirstOccurrence(List* list, void* data)
{
ListNode* node = List_FindFirstOccurrence(list, data);
if (NULL != node)
{
List_RemoveNode(list, node);
}
}
Stack* Stack_Create()
{
Stack* stack = (Stack*)kmalloc(sizeof(Stack));
memset((uint8*)stack, 0, sizeof(Stack));
stack->list = List_Create();
return stack;
}
void Stack_Clear(Stack* stack)
{
List_Clear(stack->list);
}
void Stack_Destroy(Stack* stack)
{
List_Destroy(stack->list);
kfree(stack);
}
BOOL Stack_IsEmpty(Stack* stack)
{
return List_IsEmpty(stack->list);
}
void Stack_Push(Stack* stack, void* data)
{
List_Prepend(stack->list, data);
}
void* Stack_Pop(Stack* stack)
{
void* result = NULL;
ListNode* node = List_GetFirstNode(stack->list);
if (NULL != node)
{
result = node->data;
List_RemoveNode(stack->list, node);
}
return result;
}
Queue* Queue_Create()
{
Queue* queue = (Queue*)kmalloc(sizeof(Queue));
memset((uint8*)queue, 0, sizeof(Queue));
queue->list = List_Create();
return queue;
}
void Queue_Clear(Queue* queue)
{
List_Clear(queue->list);
}
void Queue_Destroy(Queue* queue)
{
List_Destroy(queue->list);
kfree(queue);
}
BOOL Queue_IsEmpty(Queue* queue)
{
return List_IsEmpty(queue->list);
}
void Queue_Enqueue(Queue* queue, void* data)
{
List_Append(queue->list, data);
}
void* Queue_Dequeue(Queue* stack)
{
void* result = NULL;
ListNode* node = List_GetFirstNode(stack->list);
if (NULL != node)
{
result = node->data;
List_RemoveNode(stack->list, node);
}
return result;
}

62
kernel.soso/list.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef LIST_H
#define LIST_H
#include "common.h"
#define List_Foreach(listNode, list) for (ListNode* listNode = list->head; NULL != listNode ; listNode = listNode->next)
typedef struct ListNode
{
struct ListNode* previous;
struct ListNode* next;
void* data;
} ListNode;
typedef struct List
{
struct ListNode* head;
struct ListNode* tail;
} List;
List* List_Create();
void List_Clear(List* list);
void List_Destroy(List* list);
List* List_CreateClone(List* list);
BOOL List_IsEmpty(List* list);
void List_Append(List* list, void* data);
void List_Prepend(List* list, void* data);
ListNode* List_GetFirstNode(List* list);
ListNode* List_GetLastNode(List* list);
ListNode* List_FindFirstOccurrence(List* list, void* data);
int List_FindFirstOccurrenceIndex(List* list, void* data);
int List_GetCount(List* list);
void List_RemoveNode(List* list, ListNode* node);
void List_RemoveFirstNode(List* list);
void List_RemoveLastNode(List* list);
void List_RemoveFirstOccurrence(List* list, void* data);
typedef struct Stack
{
List* list;
} Stack;
Stack* Stack_Create();
void Stack_Clear(Stack* stack);
void Stack_Destroy(Stack* stack);
BOOL Stack_IsEmpty(Stack* stack);
void Stack_Push(Stack* stack, void* data);
void* Stack_Pop(Stack* stack);
typedef struct Queue
{
List* list;
} Queue;
Queue* Queue_Create();
void Queue_Clear(Queue* queue);
void Queue_Destroy(Queue* queue);
BOOL Queue_IsEmpty(Queue* queue);
void Queue_Enqueue(Queue* queue, void* data);
void* Queue_Dequeue(Queue* stack);
#endif // LIST_H

234
kernel.soso/main.c Normal file
View File

@ -0,0 +1,234 @@
#include "screen.h"
#include "descriptortables.h"
#include "timer.h"
#include "multiboot.h"
#include "fs.h"
#include "syscalls.h"
#include "serial.h"
#include "isr.h"
#include "vmm.h"
#include "alloc.h"
#include "process.h"
#include "keyboard.h"
#include "ttydriver.h"
#include "devfs.h"
#include "systemfs.h"
#include "pipe.h"
#include "sharedmemory.h"
#include "random.h"
#include "null.h"
#include "elf.h"
#include "debugprint.h"
#include "ramdisk.h"
#include "fatfilesystem.h"
#include "vbe.h"
#include "fifobuffer.h"
#include "gfx.h"
#include "mouse.h"
#include "sleep.h"
extern uint32 _start;
extern uint32 _end;
uint32 gPhysicalKernelStartAddress = (uint32)&_start;
uint32 gPhysicalKernelEndAddress = (uint32)&_end;
static void* locateInitrd(struct Multiboot *mbi, uint32* size)
{
if (mbi->mods_count > 0)
{
uint32 startLocation = *((uint32*)mbi->mods_addr);
uint32 endLocation = *(uint32*)(mbi->mods_addr + 4);
*size = endLocation - startLocation;
return (void*)startLocation;
}
return NULL;
}
void printUsageInfo()
{
char buffer[164];
sprintf(buffer, "Used kheap:%d", getKernelHeapUsed());
Screen_Print(0, 60, buffer);
sprintf(buffer, "Pages:%d/%d ", getUsedPageCount(), getTotalPageCount());
Screen_Print(1, 60, buffer);
sprintf(buffer, "Uptime:%d sec ", getUptimeSeconds());
Screen_Print(2, 60, buffer);
Thread* p = getMainKernelThread();
int line = 3;
sprintf(buffer, "[idle] cs:%d ", p->totalContextSwitchCount);
Screen_Print(line++, 60, buffer);
p = p->next;
while (p != NULL)
{
sprintf(buffer, "thread:%d cs:%d ", p->threadId, p->totalContextSwitchCount);
Screen_Print(line++, 60, buffer);
p = p->next;
}
}
int executeFile(const char *path, char *const argv[], char *const envp[], FileSystemNode* tty)
{
int result = -1;
Process* process = getCurrentThread()->owner;
if (process)
{
FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(path, process);
if (node)
{
File* f = open_fs(node, 0);
if (f)
{
void* image = kmalloc(node->length);
int32 bytesRead = read_fs(f, node->length, image);
if (bytesRead > 0)
{
Process* newProcess = createUserProcessFromElfData("userProcess", image, argv, envp, process, tty);
if (newProcess)
{
result = newProcess->pid;
}
}
close_fs(f);
kfree(image);
}
}
}
return result;
}
void printAsciiArt()
{
printkf(" ________ ________ ________ ________ \n");
printkf(" |\\ ____\\ |\\ __ \\ |\\ ____\\ |\\ __ \\ \n");
printkf(" \\ \\ \\___|_ \\ \\ \\|\\ \\ \\ \\ \\___|_ \\ \\ \\|\\ \\ \n");
printkf(" \\ \\_____ \\ \\ \\ \\\\\\ \\ \\ \\_____ \\ \\ \\ \\\\\\ \\ \n");
printkf(" \\|____|\\ \\ \\ \\ \\\\\\ \\ \\|____|\\ \\ \\ \\ \\\\\\ \\ \n");
printkf(" ____\\_\\ \\ \\ \\_______\\ ____\\_\\ \\ \\ \\_______\\\n");
printkf(" |\\_________\\ \\|_______| |\\_________\\ \\|_______|\n");
printkf(" \\|_________| \\|_________| \n");
printkf("\n");
}
int kmain(struct Multiboot *mboot_ptr)
{
int stack = 5;
initializeDescriptorTables();
initializeSerial();
uint32 memoryKb = mboot_ptr->mem_upper;//96*1024;
initializeMemory(memoryKb);
initializeVFS();
initializeDevFS();
if (MULTIBOOT_FRAMEBUFFER_TYPE_RGB == mboot_ptr->framebuffer_type)
{
Gfx_Initialize((uint32*)(uint32)mboot_ptr->framebuffer_addr, mboot_ptr->framebuffer_width, mboot_ptr->framebuffer_height, mboot_ptr->framebuffer_bpp / 32, mboot_ptr->framebuffer_pitch);
initializeTTYs(TRUE);
}
else
{
initializeTTYs(FALSE);
}
//printkf works after TTY initialization
printAsciiArt();
printkf("Lower Memory: %d KB\n", mboot_ptr->mem_lower);
printkf("Upper Memory: %d KB\n", mboot_ptr->mem_upper);
printkf("Memory initialized for %d MB\n", memoryKb / 1024);
printkf("Kernel start: %x - end:%x\n", gPhysicalKernelStartAddress, gPhysicalKernelEndAddress);
printkf("Initial stack: %x\n", &stack);
printkf("Video: %dx%dx%d Pitch:%d\n", mboot_ptr->framebuffer_width, mboot_ptr->framebuffer_height, mboot_ptr->framebuffer_bpp, mboot_ptr->framebuffer_pitch);
initializeSystemFS();
initializePipes();
initializeSharedMemory();
initializeTasking();
initialiseSyscalls();
initializeTimer();
initializeKeyboard();
initializeMouse();
if (0 != mboot_ptr->cmdline)
{
printkf("Kernel cmdline:%s\n", (char*)mboot_ptr->cmdline);
}
Debug_initialize("/dev/tty9");
Serial_PrintF("pitch:%d\n", mboot_ptr->framebuffer_pitch);
initializeRandom();
initializeNull();
createRamdisk("ramdisk1", 20*1024*1024);
initializeFatFileSystem();
printkf("System started!\n");
char* argv[] = {"shell", NULL};
char* envp[] = {"HOME=/", "PATH=/initrd", NULL};
uint32 initrdSize = 0;
uint8* initrdLocation = locateInitrd(mboot_ptr, &initrdSize);
if (initrdLocation == NULL)
{
PANIC("Initrd not found!\n");
}
else
{
printkf("Initrd found at %x (%d bytes)\n", initrdLocation, initrdSize);
memcpy((uint8*)*(uint32*)getFileSystemNode("/dev/ramdisk1")->privateNodeData, initrdLocation, initrdSize);
BOOL mountSuccess = mountFileSystem("/dev/ramdisk1", "/initrd", "fat", 0, 0);
if (mountSuccess)
{
printkf("Starting shell on TTYs\n");
executeFile("/initrd/init", argv, envp, getFileSystemNode("/dev/tty1"));
}
else
{
printkf("Mounting initrd failed!\n");
}
}
enableScheduler();
enableInterrupts();
while(TRUE)
{
//Idle thread
halt();
}
return 0;
}

51
kernel.soso/message.c Normal file
View File

@ -0,0 +1,51 @@
#include "message.h"
#include "process.h"
#include "fifobuffer.h"
void sendMesage(Thread* thread, SosoMessage* message)
{
Spinlock_Lock(&(thread->messageQueueLock));
FifoBuffer_enqueue(thread->messageQueue, (uint8*)message, sizeof(SosoMessage));
Spinlock_Unlock(&(thread->messageQueueLock));
}
uint32 getMessageQueueCount(Thread* thread)
{
int result = 0;
Spinlock_Lock(&(thread->messageQueueLock));
result = FifoBuffer_getSize(thread->messageQueue) / sizeof(SosoMessage);
Spinlock_Unlock(&(thread->messageQueueLock));
return result;
}
//returns remaining message count
int32 getNextMessage(Thread* thread, SosoMessage* message)
{
uint32 result = -1;
Spinlock_Lock(&(thread->messageQueueLock));
result = FifoBuffer_getSize(thread->messageQueue) / sizeof(SosoMessage);
if (result > 0)
{
FifoBuffer_dequeue(thread->messageQueue, (uint8*)message, sizeof(SosoMessage));
--result;
}
else
{
result = -1;
}
Spinlock_Unlock(&(thread->messageQueueLock));
return result;
}

16
kernel.soso/message.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include "common.h"
#include "commonuser.h"
typedef struct Thread Thread;
void sendMesage(Thread* thread, SosoMessage* message);
uint32 getMessageQueueCount(Thread* thread);
//returns remaining message count
int32 getNextMessage(Thread* thread, SosoMessage* message);
#endif // MESSAGE_H

203
kernel.soso/mouse.c Normal file
View File

@ -0,0 +1,203 @@
#include "mouse.h"
#include "isr.h"
#include "common.h"
#include "device.h"
#include "alloc.h"
#include "devfs.h"
#include "list.h"
#include "fifobuffer.h"
#include "spinlock.h"
static void handleMouseInterrupt(Registers *regs);
static uint8 gMouseByteCounter = 0;
static void prepareForRead();
static void prepareForWrite();
static void writeMouse(uint8 data);
static void handleMouseInterrupt(Registers *regs);
static BOOL mouse_open(File *file, uint32 flags);
static void mouse_close(File *file);
static int32 mouse_read(File *file, uint32 size, uint8 *buffer);
#define MOUSE_PACKET_SIZE 3
uint8 gMousePacket[MOUSE_PACKET_SIZE];
static List* gReaders = NULL;
static Spinlock gReadersLock;
void initializeMouse()
{
Device device;
memset((uint8*)&device, 0, sizeof(Device));
strcpy(device.name, "psaux");
device.deviceType = FT_CharacterDevice;
device.open = mouse_open;
device.close = mouse_close;
device.read = mouse_read;
registerInterruptHandler(IRQ12, handleMouseInterrupt);
registerDevice(&device);
memset(gMousePacket, 0, MOUSE_PACKET_SIZE);
gReaders = List_Create();
Spinlock_Init(&gReadersLock);
prepareForWrite();
outb(0x64, 0x20); //get status command
uint8 status = inb(0x60);
status = status | 2; //enable IRQ12
outb(0x64, 0x60); //set status command
outb(0x60, status);
outb(0x64, 0xA8); //enable Auxiliary Device command
writeMouse(0xF4); //0xF4: Enable Packet Streaming
}
static BOOL mouse_open(File *file, uint32 flags)
{
FifoBuffer* fifo = FifoBuffer_create(60);
file->privateData = (void*)fifo;
Spinlock_Lock(&gReadersLock);
List_Append(gReaders, file);
Spinlock_Unlock(&gReadersLock);
return TRUE;
}
static void mouse_close(File *file)
{
Spinlock_Lock(&gReadersLock);
List_RemoveFirstOccurrence(gReaders, file);
Spinlock_Unlock(&gReadersLock);
FifoBuffer* fifo = (FifoBuffer*)file->privateData;
FifoBuffer_destroy(fifo);
}
static int32 mouse_read(File *file, uint32 size, uint8 *buffer)
{
FifoBuffer* fifo = (FifoBuffer*)file->privateData;
while (FifoBuffer_getSize(fifo) < MOUSE_PACKET_SIZE)
{
file->thread->state = TS_WAITIO;
file->thread->state_privateData = mouse_read;
enableInterrupts();
halt();
}
disableInterrupts();
uint32 available = FifoBuffer_getSize(fifo);
uint32 smaller = MIN(available, size);
FifoBuffer_dequeue(fifo, buffer, smaller);
return smaller;
}
static void prepareForRead()
{
//https://wiki.osdev.org/Mouse_Input
//Bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set
int32 tryCount = 1000;
uint8 data = 0;
do
{
data = inb(0x64);
} while (((data & 0x01) == 0) && --tryCount > 0);
}
static void prepareForWrite()
{
//https://wiki.osdev.org/Mouse_Input
//All output to port 0x60 or 0x64 must be preceded by waiting for bit 1 (value=2) of port 0x64 to become clear
int32 tryCount = 1000;
uint8 data = 0;
do
{
data = inb(0x64);
} while (((data & 0x02) != 0) && --tryCount > 0);
}
static void writeMouse(uint8 data)
{
prepareForWrite();
outb(0x64, 0xD4);
prepareForWrite();
outb(0x60, data);
}
static void handleMouseInterrupt(Registers *regs)
{
uint8 status = 0;
//0x20 (5th bit is mouse bit)
//read from 0x64, if its mouse bit is 1 then data is available at 0x60!
int32 tryCount = 1000;
do
{
status = inb(0x64);
} while (((status & 0x20) == 0) && --tryCount > 0);
uint8 data = inb(0x60);
gMousePacket[gMouseByteCounter] = data;
gMouseByteCounter += 1;
if (gMouseByteCounter == MOUSE_PACKET_SIZE)
{
gMouseByteCounter = 0;
Spinlock_Lock(&gReadersLock);
//Wake readers
List_Foreach(n, gReaders)
{
File* file = n->data;
FifoBuffer* fifo = (FifoBuffer*)file->privateData;
FifoBuffer_enqueue(fifo, gMousePacket, MOUSE_PACKET_SIZE);
if (file->thread->state == TS_WAITIO)
{
if (file->thread->state_privateData == mouse_read)
{
file->thread->state = TS_RUN;
file->thread->state_privateData = NULL;
}
}
}
Spinlock_Unlock(&gReadersLock);
}
//printkf("mouse:%d\n", data);
}

6
kernel.soso/mouse.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef MOUSE_H
#define MOUSE_H
void initializeMouse();
#endif // MOUSE_H

45
kernel.soso/multiboot.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef MULTIBOOT_H
#define MULTIBOOT_H
#include "common.h"
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
struct Multiboot
{
uint32 flags;
uint32 mem_lower;
uint32 mem_upper;
uint32 boot_device;
uint32 cmdline;
uint32 mods_count;
uint32 mods_addr;
uint32 num;
uint32 size;
uint32 addr;
uint32 shndx;
uint32 mmap_length;
uint32 mmap_addr;
uint32 drives_length;
uint32 drives_addr;
uint32 config_table;
uint32 boot_loader_name;
uint32 apm_table;
uint32 vbe_control_info;
uint32 vbe_mode_info;
uint16 vbe_mode;
uint16 vbe_interface_seg;
uint16 vbe_interface_off;
uint16 vbe_interface_len;
uint64 framebuffer_addr;
uint32 framebuffer_pitch;
uint32 framebuffer_width;
uint32 framebuffer_height;
uint8 framebuffer_bpp;
uint8 framebuffer_type;
} __attribute__((packed));
#endif

22
kernel.soso/null.c Normal file
View File

@ -0,0 +1,22 @@
#include "null.h"
#include "devfs.h"
#include "device.h"
#include "common.h"
static BOOL null_open(File *file, uint32 flags);
void initializeNull()
{
Device device;
memset((uint8*)&device, 0, sizeof(Device));
strcpy(device.name, "null");
device.deviceType = FT_CharacterDevice;
device.open = null_open;
registerDevice(&device);
}
static BOOL null_open(File *file, uint32 flags)
{
return TRUE;
}

6
kernel.soso/null.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef NULL_H
#define NULL_H
void initializeNull();
#endif // NULL_H

258
kernel.soso/pipe.c Normal file
View File

@ -0,0 +1,258 @@
#include "list.h"
#include "pipe.h"
#include "fs.h"
#include "alloc.h"
#include "fifobuffer.h"
static List* gPipeList = NULL;
static FileSystemNode* gPipesRoot = NULL;
static FileSystemDirent gDirent;
typedef struct Pipe
{
char name[32];
FifoBuffer* buffer;
FileSystemNode* fsNode;
List* accessingThreads;
} Pipe;
static BOOL pipes_open(File *file, uint32 flags);
static FileSystemDirent *pipes_readdir(FileSystemNode *node, uint32 index);
static FileSystemNode *pipes_finddir(FileSystemNode *node, char *name);
void initializePipes()
{
gPipeList = List_Create();
gPipesRoot = getFileSystemNode("/system/pipes");
if (NULL == gPipesRoot)
{
WARNING("/system/pipes not found!!");
}
else
{
gPipesRoot->open = pipes_open;
gPipesRoot->finddir = pipes_finddir;
gPipesRoot->readdir = pipes_readdir;
}
}
static BOOL pipes_open(File *file, uint32 flags)
{
return TRUE;
}
static FileSystemDirent *pipes_readdir(FileSystemNode *node, uint32 index)
{
int counter = 0;
List_Foreach (n, gPipeList)
{
Pipe* p = (Pipe*)n->data;
if (counter == index)
{
strcpy(gDirent.name, p->name);
gDirent.fileType = FT_Pipe;
return &gDirent;
}
++counter;
}
return NULL;
}
static FileSystemNode *pipes_finddir(FileSystemNode *node, char *name)
{
List_Foreach (n, gPipeList)
{
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0)
{
return p->fsNode;
}
}
return NULL;
}
static BOOL pipe_open(File *file, uint32 flags)
{
beginCriticalSection();
Pipe* pipe = file->node->privateNodeData;
List_Append(pipe->accessingThreads, file->thread);
endCriticalSection();
return TRUE;
}
static void pipe_close(File *file)
{
beginCriticalSection();
Pipe* pipe = file->node->privateNodeData;
List_RemoveFirstOccurrence(pipe->accessingThreads, file->thread);
endCriticalSection();
}
static void blockAccessingThreads(Pipe* pipe)
{
disableInterrupts();
List_Foreach (n, pipe->accessingThreads)
{
Thread* reader = n->data;
reader->state = TS_WAITIO;
reader->state_privateData = pipe;
}
enableInterrupts();
halt();
}
static void wakeupAccessingThreads(Pipe* pipe)
{
beginCriticalSection();
List_Foreach (n, pipe->accessingThreads)
{
Thread* reader = n->data;
if (reader->state == TS_WAITIO)
{
if (reader->state_privateData == pipe)
{
reader->state = TS_RUN;
}
}
}
endCriticalSection();
}
static int32 pipe_read(File *file, uint32 size, uint8 *buffer)
{
if (0 == size || NULL == buffer)
{
return -1;
}
Pipe* pipe = file->node->privateNodeData;
uint32 used = 0;
while ((used = FifoBuffer_getSize(pipe->buffer)) < size)
{
blockAccessingThreads(pipe);
}
disableInterrupts();
int32 readBytes = FifoBuffer_dequeue(pipe->buffer, buffer, size);
wakeupAccessingThreads(pipe);
return readBytes;
}
static int32 pipe_write(File *file, uint32 size, uint8 *buffer)
{
if (0 == size || NULL == buffer)
{
return -1;
}
Pipe* pipe = file->node->privateNodeData;
uint32 free = 0;
while ((free = FifoBuffer_getFree(pipe->buffer)) < size)
{
blockAccessingThreads(pipe);
}
disableInterrupts();
int32 bytesWritten = FifoBuffer_enqueue(pipe->buffer, buffer, size);
wakeupAccessingThreads(pipe);
return bytesWritten;
}
BOOL createPipe(const char* name, uint32 bufferSize)
{
List_Foreach (n, gPipeList)
{
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0)
{
return FALSE;
}
}
Pipe* pipe = (Pipe*)kmalloc(sizeof(Pipe));
memset((uint8*)pipe, 0, sizeof(Pipe));
strcpy(pipe->name, name);
pipe->buffer = FifoBuffer_create(bufferSize);
pipe->accessingThreads = List_Create();
pipe->fsNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
memset((uint8*)pipe->fsNode, 0, sizeof(FileSystemNode));
pipe->fsNode->privateNodeData = pipe;
pipe->fsNode->open = pipe_open;
pipe->fsNode->close = pipe_close;
pipe->fsNode->read = pipe_read;
pipe->fsNode->write = pipe_write;
List_Append(gPipeList, pipe);
return TRUE;
}
BOOL destroyPipe(const char* name)
{
List_Foreach (n, gPipeList)
{
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0)
{
List_RemoveFirstOccurrence(gPipeList, p);
FifoBuffer_destroy(p->buffer);
List_Destroy(p->accessingThreads);
kfree(p->fsNode);
kfree(p);
return TRUE;
}
}
return FALSE;
}
BOOL existsPipe(const char* name)
{
List_Foreach (n, gPipeList)
{
Pipe* p = (Pipe*)n->data;
if (strcmp(name, p->name) == 0)
{
return TRUE;
}
}
return FALSE;
}

11
kernel.soso/pipe.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef PIPE_H
#define PIPE_H
#include "common.h"
void initializePipes();
BOOL createPipe(const char* name, uint32 bufferSize);
BOOL destroyPipe(const char* name);
BOOL existsPipe(const char* name);
#endif // PIPE_H

812
kernel.soso/process.c Normal file
View File

@ -0,0 +1,812 @@
#include "process.h"
#include "common.h"
#include "alloc.h"
#include "vmm.h"
#include "descriptortables.h"
#include "elf.h"
#include "screen.h"
#include "debugprint.h"
#include "isr.h"
#include "timer.h"
#include "message.h"
#define MESSAGE_QUEUE_SIZE 64
Process* gKernelProcess = NULL;
Thread* gFirstThread = NULL;
Thread* gCurrentThread = NULL;
Thread* gDestroyedThread = NULL;
uint32 gProcessIdGenerator = 0;
uint32 gThreadIdGenerator = 0;
uint32 gSystemContextSwitchCount = 0;
uint32 gLastUptimeSeconds = 0;
extern Tss gTss;
uint32 generateProcessId()
{
return gProcessIdGenerator++;
}
uint32 generateThreadId()
{
return gThreadIdGenerator++;
}
uint32 getSystemContextSwitchCount()
{
return gSystemContextSwitchCount;
}
void initializeTasking()
{
Process* process = (Process*)kmalloc(sizeof(Process));
memset((uint8*)process, 0, sizeof(Process));
strcpy(process->name, "[kernel]");
process->pid = generateProcessId();
process->pd = (uint32*) KERN_PAGE_DIRECTORY;
process->workingDirectory = getFileSystemRootNode();
gKernelProcess = process;
Thread* thread = (Thread*)kmalloc(sizeof(Thread));
memset((uint8*)thread, 0, sizeof(Thread));
thread->owner = gKernelProcess;
thread->threadId = generateThreadId();
thread->userMode = 0;
thread->state = TS_RUN;
thread->messageQueue = FifoBuffer_create(sizeof(SosoMessage) * MESSAGE_QUEUE_SIZE);
Spinlock_Init(&(thread->messageQueueLock));
thread->regs.cr3 = (uint32) process->pd;
uint32 selector = 0x10;
thread->regs.ss = selector;
thread->regs.eflags = 0x0;
thread->regs.cs = 0x08;
thread->regs.eip = NULL;
thread->regs.ds = selector;
thread->regs.es = selector;
thread->regs.fs = selector;
thread->regs.gs = selector;
thread->regs.esp = 0; //no need because this is already main kernel thread. ESP will written to this in first schedule.
thread->kstack.ss0 = 0x10;
thread->kstack.esp0 = 0;//For kernel threads, this is not required
gFirstThread = thread;
gCurrentThread = thread;
}
static int getStringArrayItemCount(char *const array[])
{
if (NULL == array)
{
return 0;
}
int i = 0;
const char* a = array[0];
while (NULL != a)
{
a = array[++i];
}
return i;
}
static char** cloneStringArray(char *const array[])
{
int itemCount = getStringArrayItemCount(array);
char** newArray = kmalloc(sizeof(char*) * (itemCount + 1));
for (int i = 0; i < itemCount; ++i)
{
const char* str = array[i];
int len = strlen(str);
char* newStr = kmalloc(len + 1);
strcpy(newStr, str);
newArray[i] = newStr;
}
newArray[itemCount] = NULL;
return newArray;
}
static void destroyStringArray(char** array)
{
char* a = array[0];
int i = 0;
while (NULL != a)
{
kfree(a);
a = array[++i];
}
kfree(array);
}
//This function must be called within the correct page directory for target process
static void copyArgvEnvToProcess(char *const argv[], char *const envp[])
{
char** destination = (char**)USER_ARGV_ENV_LOC;
int destinationIndex = 0;
//Screen_PrintF("ARGVENV: destination:%x\n", destination);
int argvCount = getStringArrayItemCount(argv);
int envpCount = getStringArrayItemCount(envp);
//Screen_PrintF("ARGVENV: argvCount:%d envpCount:%d\n", argvCount, envpCount);
char* stringTable = (char*)USER_ARGV_ENV_LOC + sizeof(char*) * (argvCount + envpCount + 2);
//Screen_PrintF("ARGVENV: stringTable:%x\n", stringTable);
for (int i = 0; i < argvCount; ++i)
{
strcpy(stringTable, argv[i]);
destination[destinationIndex] = stringTable;
stringTable += strlen(argv[i]) + 2;
destinationIndex++;
}
destination[destinationIndex++] = NULL;
for (int i = 0; i < envpCount; ++i)
{
strcpy(stringTable, envp[i]);
destination[destinationIndex] = stringTable;
stringTable += strlen(envp[i]) + 2;
destinationIndex++;
}
destination[destinationIndex++] = NULL;
}
Process* createUserProcessFromElfData(const char* name, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty)
{
return createUserProcessEx(name, generateProcessId(), generateThreadId(), NULL, elfData, argv, envp, parent, tty);
}
Process* createUserProcessEx(const char* name, uint32 processId, uint32 threadId, Function0 func, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty)
{
printkf("createUserProcessEx: %s %d %d\n", name, processId, threadId);
if (0 == processId)
{
processId = generateProcessId();
}
if (0 == threadId)
{
threadId = generateThreadId();
}
Process* process = (Process*)kmalloc(sizeof(Process));
memset((uint8*)process, 0, sizeof(Process));
strcpy(process->name, name);
process->pid = processId;
process->pd = createPd();//our page directories are identity mapped so this is also a physical address.
process->workingDirectory = getFileSystemRootNode();
Thread* thread = (Thread*)kmalloc(sizeof(Thread));
memset((uint8*)thread, 0, sizeof(Thread));
thread->owner = process;
thread->threadId = threadId;
thread->userMode = 1;
thread->state = TS_RUN;
thread->messageQueue = FifoBuffer_create(sizeof(SosoMessage) * MESSAGE_QUEUE_SIZE);
Spinlock_Init(&(thread->messageQueueLock));
thread->regs.cr3 = (uint32) process->pd;
//Since stack grows backwards, we must allocate previous page. So lets substract a small amount.
uint32 stackp = USER_STACK-4;
if (parent)
{
process->parent = parent;
process->workingDirectory = parent->workingDirectory;
process->tty = parent->tty;
}
if (tty)
{
process->tty = tty;
}
char** newArgv = cloneStringArray(argv);
char** newEnvp = cloneStringArray(envp);
//Change memory view (page directory)
asm("mov %0, %%eax; mov %%eax, %%cr3"::"m"(process->pd));
initializeProcessHeap(process);
initializeProcessMmap(process);
copyArgvEnvToProcess(newArgv, newEnvp);
destroyStringArray(newArgv);
destroyStringArray(newEnvp);
uint32 selector = 0x23;
thread->regs.ss = selector;
thread->regs.eflags = 0x0;
thread->regs.cs = 0x1B;
thread->regs.eip = (uint32)func;
thread->regs.ds = selector;
thread->regs.es = selector;
thread->regs.fs = selector;
thread->regs.gs = selector;
thread->regs.esp = stackp;
char* p_addr = getPageFrame4M();
char* v_addr = (char *) (USER_STACK - PAGESIZE_4M);
addPageToPd(process->pd, v_addr, p_addr, PG_USER);
thread->kstack.ss0 = 0x10;
uint8* stack = (uint8*)kmalloc(KERN_STACK_SIZE);
thread->kstack.esp0 = (uint32)(stack + KERN_STACK_SIZE - 4);
thread->kstack.stackStart = (uint32)stack;
Thread* p = gCurrentThread;
while (p->next != NULL)
{
p = p->next;
}
p->next = thread;
if (elfData)
{
printkf("about to load ELF data\n");
uint32 startLocation = loadElf((char*)elfData);
if (startLocation > 0)
{
thread->regs.eip = startLocation;
}
}
//Restore memory view (page directory)
asm("mov %0, %%eax ;mov %%eax, %%cr3":: "m"(gCurrentThread->regs.cr3));
open_fs_forProcess(thread, process->tty, 0);//0: standard input
open_fs_forProcess(thread, process->tty, 0);//1: standard output
open_fs_forProcess(thread, process->tty, 0);//2: standard error
printkf("running process %d\n", process->pid);
return process;
}
//This function should be called in interrupts disabled state
void destroyThread(Thread* thread)
{
Spinlock_Lock(&(thread->messageQueueLock));
//TODO: signal the process somehow
Thread* previousThread = getPreviousThread(thread);
if (NULL != previousThread)
{
previousThread->next = thread->next;
kfree((void*)thread->kstack.stackStart);
FifoBuffer_destroy(thread->messageQueue);
Debug_PrintF("destroying thread %d\n", thread->threadId);
kfree(thread);
if (thread == gCurrentThread)
{
gCurrentThread = NULL;
}
}
else
{
printkf("Could not find previous thread for thread %d\n", thread->threadId);
PANIC("This should not be happened!\n");
}
}
//This function should be called in interrupts disabled state
void destroyProcess(Process* process)
{
Thread* thread = gFirstThread;
Thread* previous = NULL;
while (thread)
{
if (process == thread->owner)
{
if (NULL != previous)
{
previous->next = thread->next;
kfree((void*)thread->kstack.stackStart);
Spinlock_Lock(&(thread->messageQueueLock));
FifoBuffer_destroy(thread->messageQueue);
Debug_PrintF("destroying thread id:%d (owner process %d)\n", thread->threadId, process->pid);
kfree(thread);
if (thread == gCurrentThread)
{
gCurrentThread = NULL;
}
thread = previous->next;
continue;
}
}
previous = thread;
thread = thread->next;
}
//Cleanup opened files
for (int i = 0; i < MAX_OPENED_FILES; ++i)
{
if (process->fd[i] != NULL)
{
close_fs(process->fd[i]);
}
}
if (process->parent)
{
thread = gFirstThread;
while (thread)
{
if (process->parent == thread->owner)
{
if (thread->state == TS_WAITCHILD)
{
thread->state = TS_RUN;
}
}
thread = thread->next;
}
}
Debug_PrintF("destroying process %d\n", process->pid);
destroyPd(process->pd);
kfree(process);
}
void threadStateToString(ThreadState state, uint8* buffer, uint32 bufferSize)
{
if (bufferSize < 1)
{
return;
}
buffer[0] = '\0';
if (bufferSize < 10)
{
return;
}
switch (state)
{
case TS_RUN:
strcpy((char*)buffer, "run");
break;
case TS_SLEEP:
strcpy((char*)buffer, "sleep");
break;
case TS_SUSPEND:
strcpy((char*)buffer, "suspend");
break;
case TS_WAITCHILD:
strcpy((char*)buffer, "waitchild");
break;
case TS_WAITIO:
strcpy((char*)buffer, "waitio");
break;
case TS_YIELD:
strcpy((char*)buffer, "yield");
break;
default:
break;
}
}
void waitForSchedule()
{
//Screen_PrintF("Waiting for a schedule()\n");
enableInterrupts();
while (TRUE)
{
halt();
}
disableInterrupts();
PANIC("waitForSchedule(): Should not be reached here!!!\n");
}
void yield(uint32 count)
{
gCurrentThread->yield = count;
gCurrentThread->state = TS_YIELD;
enableInterrupts();
while (gCurrentThread->yield > 0)
{
halt();
}
disableInterrupts();
}
int32 getEmptyFd(Process* process)
{
int32 result = -1;
beginCriticalSection();
for (int i = 0; i < MAX_OPENED_FILES; ++i)
{
if (process->fd[i] == NULL)
{
result = i;
break;
}
}
endCriticalSection();
return result;
}
int32 addFileToProcess(Process* process, File* file)
{
int32 result = -1;
beginCriticalSection();
//Screen_PrintF("addFileToProcess: pid:%d\n", process->pid);
for (int i = 0; i < MAX_OPENED_FILES; ++i)
{
//Screen_PrintF("addFileToProcess: i:%d fd[%d]:%x\n", i, i, process->fd[i]);
if (process->fd[i] == NULL)
{
result = i;
file->fd = i;
process->fd[i] = file;
break;
}
}
endCriticalSection();
return result;
}
int32 removeFileFromProcess(Process* process, File* file)
{
int32 result = -1;
beginCriticalSection();
for (int i = 0; i < MAX_OPENED_FILES; ++i)
{
if (process->fd[i] == file)
{
result = i;
process->fd[i] = NULL;
break;
}
}
endCriticalSection();
return result;
}
Thread* getThreadById(uint32 threadId)
{
Thread* p = gFirstThread;
while (p != NULL)
{
if (p->threadId == threadId)
{
return p;
}
p = p->next;
}
return NULL;
}
Thread* getPreviousThread(Thread* thread)
{
Thread* t = gFirstThread;
while (t->next != NULL)
{
if (t->next == thread)
{
return t;
}
t = t->next;
}
return NULL;
}
Thread* getMainKernelThread()
{
return gFirstThread;
}
Thread* getCurrentThread()
{
return gCurrentThread;
}
BOOL isThreadValid(Thread* thread)
{
Thread* p = gFirstThread;
while (p != NULL)
{
if (p == thread)
{
return TRUE;
}
p = p->next;
}
return FALSE;
}
BOOL isProcessValid(Process* process)
{
Thread* p = gFirstThread;
while (p != NULL)
{
if (p->owner == process)
{
return TRUE;
}
p = p->next;
}
return FALSE;
}
static void switchToTask(Thread* current, int mode);
static void updateMetrics(Thread* thread)
{
uint32 seconds = getUptimeSeconds();
if (seconds > gLastUptimeSeconds)
{
gLastUptimeSeconds = seconds;
Thread* t = gFirstThread;
while (t != NULL)
{
t->contextSwitchCount = t->totalContextSwitchCount - t->totalContextSwitchCountPrevious;
t->totalContextSwitchCountPrevious = t->totalContextSwitchCount;
t = t->next;
}
}
++gSystemContextSwitchCount;
++thread->totalContextSwitchCount;
}
void schedule(TimerInt_Registers* registers)
{
Thread* current = gCurrentThread;
if (NULL != current)
{
if (current->next == NULL && current == gFirstThread)
{
//We are the only process, no need to schedule
return;
}
current->regs.eflags = registers->eflags;
current->regs.cs = registers->cs;
current->regs.eip = registers->eip;
current->regs.eax = registers->eax;
current->regs.ecx = registers->ecx;
current->regs.edx = registers->edx;
current->regs.ebx = registers->ebx;
current->regs.ebp = registers->ebp;
current->regs.esi = registers->esi;
current->regs.edi = registers->edi;
current->regs.ds = registers->ds;
current->regs.es = registers->es;
current->regs.fs = registers->fs;
current->regs.gs = registers->gs;
if (current->regs.cs != 0x08)
{
//Debug_PrintF("schedule() - 2.1\n");
current->regs.esp = registers->esp_if_privilege_change;
current->regs.ss = registers->ss_if_privilege_change;
}
else
{
//Debug_PrintF("schedule() - 2.2\n");
current->regs.esp = registers->esp + 12;
current->regs.ss = gTss.ss0;
}
//Save the TSS from the old process
current->kstack.ss0 = gTss.ss0;
current->kstack.esp0 = gTss.esp0;
current = current->next;
while (NULL != current)
{
if (current->state == TS_YIELD)
{
if (current->yield > 0)
{
--current->yield;
}
if (current->yield == 0)
{
current->state = TS_RUN;
}
}
if (current->state == TS_SLEEP)
{
uint32 uptime = getUptimeMilliseconds();
uint32 target = (uint32)current->state_privateData;
if (uptime >= target)
{
current->state = TS_RUN;
current->state_privateData = NULL;
}
}
if (current->state == TS_RUN)
{
break;
}
current = current->next;
}
if (current == NULL)
{
//reached last process returning to first
current = gFirstThread;
}
}
else
{
//current is NULL. This means thread is destroyed, so start from the begining
current = gFirstThread;
}
gCurrentThread = current;//Now gCurrentThread is the thread we are about to schedule to
/*
if (gCurrentThread->threadId == 5)
{
Screen_PrintF("I am scheduling to %d and its EIP is %x\n", gCurrentThread->threadId, gCurrentThread->regs.eip);
}
*/
updateMetrics(current);
if (current->regs.cs != 0x08)
{
switchToTask(current, USERMODE);
}
else
{
switchToTask(current, KERNELMODE);
}
}
//The mode indicates whether this process was in user mode or kernel mode
//When it was previously interrupted by the scheduler.
static void switchToTask(Thread* current, int mode)
{
uint32 kesp, eflags;
uint16 kss, ss, cs;
//Set TSS values
gTss.ss0 = current->kstack.ss0;
gTss.esp0 = current->kstack.esp0;
ss = current->regs.ss;
cs = current->regs.cs;
eflags = (current->regs.eflags | 0x200) & 0xFFFFBFFF;
if (mode == USERMODE)
{
kss = current->kstack.ss0;
kesp = current->kstack.esp0;
}
else
{
kss = current->regs.ss;
kesp = current->regs.esp;
}
//switchTask is in task.asm
asm(" mov %0, %%ss; \
mov %1, %%esp; \
cmpl %[KMODE], %[mode]; \
je nextt; \
push %2; \
push %3; \
nextt: \
push %4; \
push %5; \
push %6; \
push %7; \
ljmp $0x08, $switchTask"
:: \
"m"(kss), \
"m"(kesp), \
"m"(ss), \
"m"(current->regs.esp), \
"m"(eflags), \
"m"(cs), \
"m"(current->regs.eip), \
"m"(current), \
[KMODE] "i"(KERNELMODE), \
[mode] "g"(mode)
);
}

138
kernel.soso/process.h Normal file
View File

@ -0,0 +1,138 @@
#ifndef PROCESS_H
#define PROCESS_H
#define KERNELMODE 0
#define USERMODE 1
#define MAX_OPENED_FILES 20
#include "common.h"
#include "fs.h"
#include "fifobuffer.h"
#include "spinlock.h"
typedef enum ThreadState
{
TS_RUN,
TS_WAITIO,
TS_WAITCHILD,
TS_SLEEP,
TS_SUSPEND,
TS_YIELD
} ThreadState;
struct Process
{
char name[32];
uint32 pid;
uint32 *pd;
uint32 b_exec;
uint32 e_exec;
uint32 b_bss;
uint32 e_bss;
char *heapBegin;
char *heapEnd;
char *heapNextUnallocatedPageBegin;
uint8 mmappedVirtualMemory[RAM_AS_4M_PAGES / 8];
uint32 signal;
void* sigfn[32];
FileSystemNode* tty;
FileSystemNode* workingDirectory;
//Thread* mainThread;
Process* parent;
// Save exit status of child process that most recently performed exit().
int32 childExitStatusPresent; // boolean
int32 childExitStatus;
File* fd[MAX_OPENED_FILES];
} __attribute__ ((packed));
typedef struct Process Process;
struct Thread
{
uint32 threadId;
struct
{
uint32 eax, ecx, edx, ebx;
uint32 esp, ebp, esi, edi;
uint32 eip, eflags;
uint32 cs:16, ss:16, ds:16, es:16, fs:16, gs:16;
uint32 cr3;
} regs __attribute__ ((packed));
struct
{
uint32 esp0;
uint16 ss0;
uint32 stackStart;
} kstack __attribute__ ((packed));
uint32 userMode;
ThreadState state;
Process* owner;
uint32 yield;
uint32 contextSwitchCount;
uint32 totalContextSwitchCount;
uint32 totalContextSwitchCountPrevious;
void* state_privateData;
FifoBuffer* messageQueue;
Spinlock messageQueueLock;
struct Thread* next;
};
typedef struct Thread Thread;
typedef struct TimerInt_Registers
{
uint32 gs, fs, es, ds;
uint32 edi, esi, ebp, esp, ebx, edx, ecx, eax; //pushed by pushad
uint32 eip, cs, eflags, esp_if_privilege_change, ss_if_privilege_change; //pushed by the CPU
} TimerInt_Registers;
typedef void (*Function0)();
void initializeTasking();
Process* createUserProcessFromElfData(const char* name, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty);
Process* createUserProcessEx(const char* name, uint32 processId, uint32 threadId, Function0 func, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty);
void destroyThread(Thread* thread);
void destroyProcess(Process* process);
void threadStateToString(ThreadState state, uint8* buffer, uint32 bufferSize);
void waitForSchedule();
void yield(uint32 count);
int32 getEmptyFd(Process* process);
int32 addFileToProcess(Process* process, File* file);
int32 removeFileFromProcess(Process* process, File* file);
Thread* getThreadById(uint32 threadId);
Thread* getPreviousThread(Thread* thread);
Thread* getMainKernelThread();
Thread* getCurrentThread();
void schedule(TimerInt_Registers* registers);
BOOL isThreadValid(Thread* thread);
BOOL isProcessValid(Process* process);
uint32 getSystemContextSwitchCount();
#endif // PROCESS_H

120
kernel.soso/ramdisk.c Normal file
View File

@ -0,0 +1,120 @@
#include "ramdisk.h"
#include "alloc.h"
#include "fs.h"
#include "devfs.h"
typedef struct Ramdisk
{
uint8* buffer;
uint32 size;
} Ramdisk;
#define RAMDISK_BLOCKSIZE 512
static BOOL open(File *file, uint32 flags);
static void close(File *file);
static int32 readBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer);
static int32 writeBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer);
static int32 ioctl(File *node, int32 request, void * argp);
BOOL createRamdisk(const char* devName, uint32 size)
{
Ramdisk* ramdisk = kmalloc(sizeof(Ramdisk));
ramdisk->size = size;
ramdisk->buffer = kmalloc(size);
Device device;
memset((uint8*)&device, 0, sizeof(device));
strcpy(device.name, devName);
device.deviceType = FT_BlockDevice;
device.open = open;
device.close = close;
device.readBlock = readBlock;
device.writeBlock = writeBlock;
device.ioctl = ioctl;
device.privateData = ramdisk;
if (registerDevice(&device))
{
return TRUE;
}
kfree(ramdisk->buffer);
kfree(ramdisk);
return FALSE;
}
static BOOL open(File *file, uint32 flags)
{
return TRUE;
}
static void close(File *file)
{
}
static int32 readBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer)
{
Ramdisk* ramdisk = (Ramdisk*)node->privateNodeData;
uint32 location = blockNumber * RAMDISK_BLOCKSIZE;
uint32 size = count * RAMDISK_BLOCKSIZE;
if (location + size > ramdisk->size)
{
return -1;
}
beginCriticalSection();
memcpy(buffer, ramdisk->buffer + location, size);
endCriticalSection();
return 0;
}
static int32 writeBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer)
{
Ramdisk* ramdisk = (Ramdisk*)node->privateNodeData;
uint32 location = blockNumber * RAMDISK_BLOCKSIZE;
uint32 size = count * RAMDISK_BLOCKSIZE;
if (location + size > ramdisk->size)
{
return -1;
}
beginCriticalSection();
memcpy(ramdisk->buffer + location, buffer, size);
endCriticalSection();
return 0;
}
static int32 ioctl(File *node, int32 request, void * argp)
{
Ramdisk* ramdisk = (Ramdisk*)node->node->privateNodeData;
uint32* result = (uint32*)argp;
switch (request)
{
case IC_GetSectorCount:
*result = ramdisk->size / RAMDISK_BLOCKSIZE;
return 0;
break;
case IC_GetSectorSizeInBytes:
*result = RAMDISK_BLOCKSIZE;
return 0;
break;
default:
break;
}
return -1;
}

8
kernel.soso/ramdisk.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef RAMDISK_H
#define RAMDISK_H
#include "common.h"
BOOL createRamdisk(const char* devName, uint32 size);
#endif // RAMDISK_H

62
kernel.soso/random.c Normal file
View File

@ -0,0 +1,62 @@
#include "random.h"
#include "devfs.h"
#include "device.h"
#include "common.h"
#include "process.h"
#include "sleep.h"
static BOOL random_open(File *file, uint32 flags);
static int32 random_read(File *file, uint32 size, uint8 *buffer);
void initializeRandom()
{
Device device;
memset((uint8*)&device, 0, sizeof(Device));
strcpy(device.name, "random");
device.deviceType = FT_CharacterDevice;
device.open = random_open;
device.read = random_read;
registerDevice(&device);
}
static BOOL random_open(File *file, uint32 flags)
{
return TRUE;
}
static int32 random_read(File *file, uint32 size, uint8 *buffer)
{
if (size == 0)
{
return 0;
}
//Screen_PrintF("random_read: calling sleep\n");
//sleep(10000);
//Screen_PrintF("random_read: returned from sleep\n");
uint32 number = rand();
if (size == 1)
{
*buffer = (uint8)number;
return 1;
}
else if (size == 2 || size == 3)
{
*((uint16*)buffer) = (uint16)number;
return 2;
}
else if (size >= 4)
{
//Screen_PrintF("random_read: buffer is %x, writing %x to buffer\n", buffer, number);
*((uint32*)buffer) = number;
return 4;
}
return 0;
}

6
kernel.soso/random.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef RANDOM_H
#define RANDOM_H
void initializeRandom();
#endif // RANDOM_H

111
kernel.soso/rootfs.c Normal file
View File

@ -0,0 +1,111 @@
#include "rootfs.h"
#include "alloc.h"
static BOOL rootfs_open(File *node, uint32 flags);
static void rootfs_close(File *file);
static FileSystemNode *rootfs_finddir(FileSystemNode *node, char *name);
static struct FileSystemDirent *rootfs_readdir(FileSystemNode *node, uint32 index);
static BOOL rootfs_mkdir(FileSystemNode *node, const char *name, uint32 flags);
FileSystemNode* initializeRootFS()
{
FileSystemNode* root = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
memset((uint8*)root, 0, sizeof(FileSystemNode));
root->nodeType = FT_Directory;
root->open = rootfs_open;
root->close = rootfs_close;
root->readdir = rootfs_readdir;
root->finddir = rootfs_finddir;
root->mkdir = rootfs_mkdir;
return root;
}
static FileSystemDirent gDirent;
static BOOL rootfs_open(File *node, uint32 flags)
{
return TRUE;
}
static void rootfs_close(File *file)
{
}
static struct FileSystemDirent *rootfs_readdir(FileSystemNode *node, uint32 index)
{
FileSystemNode *n = node->firstChild;
uint32 i = 0;
while (NULL != n)
{
if (index == i)
{
gDirent.fileType = n->nodeType;
gDirent.inode = n->inode;
strcpy(gDirent.name, n->name);
return &gDirent;
}
n = n->nextSibling;
++i;
}
return NULL;
}
static FileSystemNode *rootfs_finddir(FileSystemNode *node, char *name)
{
FileSystemNode *n = node->firstChild;
while (NULL != n)
{
if (strcmp(name, n->name) == 0)
{
return n;
}
n = n->nextSibling;
}
return NULL;
}
static BOOL rootfs_mkdir(FileSystemNode *node, const char *name, uint32 flags)
{
FileSystemNode *n = node->firstChild;
while (NULL != n)
{
if (strcmp(name, n->name) == 0)
{
return FALSE;
}
n = n->nextSibling;
}
FileSystemNode* newNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
memset((uint8*)newNode, 0, sizeof(FileSystemNode));
strcpy(newNode->name, name);
newNode->nodeType = FT_Directory;
newNode->open = rootfs_open;
newNode->close = rootfs_close;
newNode->readdir = rootfs_readdir;
newNode->finddir = rootfs_finddir;
newNode->mkdir = rootfs_mkdir;
newNode->parent = node;
if (node->firstChild == NULL)
{
node->firstChild = newNode;
}
else
{
FileSystemNode *n = node->firstChild;
while (NULL != n->nextSibling)
{
n = n->nextSibling;
}
n->nextSibling = newNode;
}
return TRUE;
}

8
kernel.soso/rootfs.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef ROOTFS_H
#define ROOTFS_H
#include "fs.h"
FileSystemNode* initializeRootFS();
#endif // ROOTFS_H

99
kernel.soso/screen.c Normal file
View File

@ -0,0 +1,99 @@
#include "screen.h"
#include "common.h"
#include "serial.h"
#define SCREEN_LINE_COUNT 25
#define SCREEN_COLUMN_COUNT 80
static unsigned char *videoStart = (unsigned char*)0xB8000;
static uint16 gCurrentLine = 0;
static uint16 gCurrentColumn = 0;
static uint8 gColor = 0x0A;
void Screen_FlushFromTty(Tty* tty)
{
memcpy(videoStart, tty->buffer, SCREEN_LINE_COUNT * SCREEN_COLUMN_COUNT * 2);
Screen_MoveCursor(tty->currentLine, tty->currentColumn);
}
void Screen_Print(int row, int column, const char* text)
{
unsigned char * video = videoStart;
video += (row * SCREEN_COLUMN_COUNT + column) * 2;
while(*text != 0)
{
*video++ = *text++;
*video++ = gColor;
}
}
void Screen_SetActiveColor(uint8 color)
{
gColor = color;
}
void Screen_ApplyColor(uint8 color)
{
gColor = color;
unsigned char * video = videoStart;
int i = 0;
for (i = 0; i < SCREEN_LINE_COUNT * SCREEN_COLUMN_COUNT; ++i)
{
video++;
*video++ = gColor;
}
}
void Screen_Clear()
{
unsigned char * video = videoStart;
int i = 0;
for (i = 0; i < SCREEN_LINE_COUNT * SCREEN_COLUMN_COUNT; ++i)
{
*video++ = 0;
*video++ = gColor;
}
gCurrentLine = 0;
gCurrentColumn = 0;
}
void Screen_MoveCursor(uint16 line, uint16 column)
{
// The screen is 80 characters wide...
uint16 cursorLocation = line * SCREEN_COLUMN_COUNT + column;
outb(0x3D4, 14); // Tell the VGA board we are setting the high cursor byte.
outb(0x3D5, cursorLocation >> 8); // Send the high cursor byte.
outb(0x3D4, 15); // Tell the VGA board we are setting the low cursor byte.
outb(0x3D5, cursorLocation); // Send the low cursor byte.
gCurrentColumn = column;
gCurrentLine = line;
}
void Screen_SetCursorVisible(BOOL visible)
{
uint8 cursor = inb(0x3d5);
if (visible)
{
cursor &= ~0x20;//5th bit cleared when cursor visible
}
else
{
cursor |= 0x20;//5th bit set when cursor invisible
}
outb(0x3D5, cursor);
}
void Screen_GetCursor(uint16* line, uint16* column)
{
*line = gCurrentLine;
*column = gCurrentColumn;
}

16
kernel.soso/screen.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef SCREEN_H
#define SCREEN_H
#include "common.h"
#include "tty.h"
void Screen_FlushFromTty(Tty* tty);
void Screen_Print(int row, int column, const char* text);
void Screen_SetActiveColor(uint8 color);
void Screen_ApplyColor(uint8 color);
void Screen_Clear();
void Screen_SetCursorVisible(BOOL visible);
void Screen_MoveCursor(uint16 line, uint16 column);
void Screen_GetCursor(uint16* line, uint16* column);
#endif //SCREEN_H

97
kernel.soso/serial.c Normal file
View File

@ -0,0 +1,97 @@
#include "common.h"
#include "serial.h"
#define PORT 0x3f8 //COM1
void initializeSerial()
{
outb(PORT + 1, 0x00); // Disable all interrupts
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
outb(PORT + 1, 0x00); // (hi byte)
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
int serialReceived()
{
return inb(PORT + 5) & 1;
}
char readSerial()
{
while (serialReceived() == 0);
return inb(PORT);
}
int isTransmitEmpty()
{
return inb(PORT + 5) & 0x20;
}
void writeSerial(char a)
{
while (isTransmitEmpty() == 0);
outb(PORT,a);
}
void Serial_PrintF(const char *format, ...)
{
char **arg = (char **) &format;
char c;
char buf[20];
//arg++;
__builtin_va_list vl;
__builtin_va_start(vl, format);
while ((c = *format++) != 0)
{
if (c != '%')
writeSerial(c);
else
{
char *p;
c = *format++;
switch (c)
{
case 'x':
buf[0] = '0';
buf[1] = 'x';
//itoa (buf + 2, c, *((int *) arg++));
itoa (buf + 2, c, __builtin_va_arg(vl, int));
p = buf;
goto string;
break;
case 'd':
case 'u':
//itoa (buf, c, *((int *) arg++));
itoa (buf, c, __builtin_va_arg(vl, int));
p = buf;
goto string;
break;
case 's':
//p = *arg++;
p = __builtin_va_arg(vl, char*);
if (! p)
p = "(null)";
string:
while (*p)
writeSerial(*p++);
break;
default:
//writeSerial(*((int *) arg++));
writeSerial(__builtin_va_arg(vl, int));
break;
}
}
}
__builtin_va_end(vl);
}

8
kernel.soso/serial.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef SERIAL_H
#define SERIAL_H
void initializeSerial();
void writeSerial(char a);
void Serial_PrintF(const char *format, ...);
#endif // SERIAL_H

252
kernel.soso/sharedmemory.c Normal file
View File

@ -0,0 +1,252 @@
#include "fs.h"
#include "common.h"
#include "list.h"
#include "alloc.h"
#include "spinlock.h"
#include "vmm.h"
#include "sharedmemory.h"
static List* gShmList = NULL;
static Spinlock gShmListLock;
static FileSystemNode* gShmRoot = NULL;
static FileSystemDirent gDirent;
static BOOL sharedmemorydir_open(File *file, uint32 flags);
static FileSystemDirent *sharedmemorydir_readdir(FileSystemNode *node, uint32 index);
static FileSystemNode *sharedmemorydir_finddir(FileSystemNode *node, char *name);
typedef struct SharedMemory
{
FileSystemNode* node;
List* physicalAddressList;
Spinlock physicalAddressListLock;
//TODO: permissions
} SharedMemory;
void initializeSharedMemory()
{
Spinlock_Init(&gShmListLock);
gShmList = List_Create();
gShmRoot = getFileSystemNode("/system/shm");
if (NULL == gShmRoot)
{
WARNING("/system/shm not found!!");
}
else
{
gShmRoot->open = sharedmemorydir_open;
gShmRoot->finddir = sharedmemorydir_finddir;
gShmRoot->readdir = sharedmemorydir_readdir;
}
}
static BOOL sharedmemorydir_open(File *file, uint32 flags)
{
return TRUE;
}
static FileSystemDirent *sharedmemorydir_readdir(FileSystemNode *node, uint32 index)
{
FileSystemDirent* result = NULL;
int counter = 0;
Spinlock_Lock(&gShmListLock);
List_Foreach (n, gShmList)
{
SharedMemory* p = (SharedMemory*)n->data;
if (counter == index)
{
strcpy(gDirent.name, p->node->name);
gDirent.fileType = p->node->nodeType;
result = &gDirent;
break;
}
++counter;
}
Spinlock_Unlock(&gShmListLock);
return result;
}
static FileSystemNode *sharedmemorydir_finddir(FileSystemNode *node, char *name)
{
FileSystemNode* result = NULL;
Spinlock_Lock(&gShmListLock);
List_Foreach (n, gShmList)
{
SharedMemory* p = (SharedMemory*)n->data;
if (strcmp(name, p->node->name) == 0)
{
result = p->node;
break;
}
}
Spinlock_Unlock(&gShmListLock);
return result;
}
static BOOL sharedmemory_open(File *file, uint32 flags)
{
return TRUE;
}
static void sharedmemory_unlink(File *file)
{
destroySharedMemory(file->node->name);
}
static int32 sharedmemory_ftruncate(File *file, int32 length)
{
if (length <= 0)
{
return -1;
}
SharedMemory* sharedMem = (SharedMemory*)file->node->privateNodeData;
if (0 != file->node->length)
{
//already set
return -1;
}
int pageCount = (length / PAGESIZE_4M) + 1;
Spinlock_Lock(&sharedMem->physicalAddressListLock);
for (int i = 0; i < pageCount; ++i)
{
char* pAddress = getPageFrame4M();
List_Append(sharedMem->physicalAddressList, pAddress);
}
file->node->length = length;
Spinlock_Unlock(&sharedMem->physicalAddressListLock);
return 0;
}
static void* sharedmemory_mmap(File* file, uint32 size, uint32 offset, uint32 flags)
{
void* result = NULL;
SharedMemory* sharedMem = (SharedMemory*)file->node->privateNodeData;
Spinlock_Lock(&sharedMem->physicalAddressListLock);
if (List_GetCount(sharedMem->physicalAddressList) > 0)
{
result = mapMemory(file->thread->owner, size, 0, sharedMem->physicalAddressList);
}
Spinlock_Unlock(&sharedMem->physicalAddressListLock);
return result;
}
FileSystemNode* getSharedMemoryNode(const char* name)
{
FileSystemNode* result = NULL;
Spinlock_Lock(&gShmListLock);
List_Foreach (n, gShmList)
{
SharedMemory* p = (SharedMemory*)n->data;
if (strcmp(name, p->node->name) == 0)
{
result = p->node;
break;
}
}
Spinlock_Unlock(&gShmListLock);
return result;
}
FileSystemNode* createSharedMemory(const char* name)
{
if (getSharedMemoryNode(name) != NULL)
{
return NULL;
}
SharedMemory* sharedMem = (SharedMemory*)kmalloc(sizeof(SharedMemory));
memset((uint8*)sharedMem, 0, sizeof(SharedMemory));
FileSystemNode* node = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
memset((uint8*)node, 0, sizeof(FileSystemNode));
strcpy(node->name, name);
node->nodeType = FT_CharacterDevice;
node->open = sharedmemory_open;
//TODO: node->shm_unlink = sharedmemory_unlink;
node->ftruncate = sharedmemory_ftruncate;
node->mmap = sharedmemory_mmap;
node->privateNodeData = sharedMem;
sharedMem->node = node;
sharedMem->physicalAddressList = List_Create();
Spinlock_Init(&sharedMem->physicalAddressListLock);
Spinlock_Lock(&gShmListLock);
List_Append(gShmList, sharedMem);
Spinlock_Unlock(&gShmListLock);
return node;
}
void destroySharedMemory(const char* name)
{
SharedMemory* sharedMem = NULL;
Spinlock_Lock(&gShmListLock);
List_Foreach (n, gShmList)
{
SharedMemory* p = (SharedMemory*)n->data;
if (strcmp(name, p->node->name) == 0)
{
sharedMem = (SharedMemory*)p;
break;
}
}
if (sharedMem)
{
Spinlock_Lock(&sharedMem->physicalAddressListLock);
kfree(sharedMem->node);
List_Destroy(sharedMem->physicalAddressList);
List_RemoveFirstOccurrence(gShmList, sharedMem);
Spinlock_Unlock(&sharedMem->physicalAddressListLock);
kfree(sharedMem);
}
Spinlock_Unlock(&gShmListLock);
}

View File

@ -0,0 +1,12 @@
#ifndef SHAREDMEMORY_H
#define SHAREDMEMORY_H
#include "common.h"
#include "fs.h"
void initializeSharedMemory();
FileSystemNode* createSharedMemory(const char* name);
void destroySharedMemory(const char* name);
FileSystemNode* getSharedMemoryNode(const char* name);
#endif // SHAREDMEMORY_H

17
kernel.soso/sleep.c Normal file
View File

@ -0,0 +1,17 @@
#include "sleep.h"
#include "timer.h"
void sleepMilliseconds(Thread* thread, uint32 ms)
{
uint32 uptime = getUptimeMilliseconds();
//target uptime to wakeup
uint32 target = uptime + ms;
thread->state = TS_SLEEP;
thread->state_privateData = (void*)target;
enableInterrupts();
halt();
}

9
kernel.soso/sleep.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef SLEEP_H
#define SLEEP_H
#include "common.h"
#include "process.h"
void sleepMilliseconds(Thread* thread, uint32 ms);
#endif // SLEEP_H

30
kernel.soso/spinlock.c Normal file
View File

@ -0,0 +1,30 @@
#include "spinlock.h"
static inline int32 exchangeAtomic(volatile int32* oldValueAddress, int32 newValue)
{
//no need to use lock instruction on xchg
asm volatile ("xchgl %0, %1"
: "=r"(newValue)
: "m"(*oldValueAddress), "0"(newValue)
: "memory");
return newValue;
}
void Spinlock_Init(Spinlock* spinlock)
{
*spinlock = 0;
}
void Spinlock_Lock(Spinlock* spinlock)
{
while (exchangeAtomic((int32*)spinlock, 1))
{
halt();
}
}
void Spinlock_Unlock(Spinlock* spinlock)
{
*spinlock = 0;
}

12
kernel.soso/spinlock.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef SPINLOCK_H
#define SPINLOCK_H
#include "common.h"
typedef int32 Spinlock;
void Spinlock_Init(Spinlock* spinlock);
void Spinlock_Lock(Spinlock* spinlock);
void Spinlock_Unlock(Spinlock* spinlock);
#endif // SPINLOCK_H

1163
kernel.soso/syscalls.c Normal file

File diff suppressed because it is too large Load Diff

6
kernel.soso/syscalls.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef SYSCALLS_H
#define SYSCALLS_H
void initialiseSyscalls();
#endif // SYSCALLS_H

View File

@ -0,0 +1,51 @@
#ifndef SYSCALLTABLE_H
#define SYSCALLTABLE_H
//This file will also be included by C library.
enum
{
SYS_open, // 0
SYS_close, // 1
SYS_read, // 2
SYS_write, // 3
SYS_lseek, // 4
SYS_stat, // 5
SYS_fstat, // 6
SYS_ioctl, // 7
SYS_exit, // 8
SYS_sbrk, // 9
SYS_fork, // 10
SYS_getpid, // 11
//non-posix
SYS_execute, // 12
SYS_execve, // 13
SYS_wait, // 14
SYS_kill, // 15
SYS_mount, // 16
SYS_unmount, // 17
SYS_mkdir, // 18
SYS_rmdir, // 19
SYS_getdents, // 20
SYS_getWorkingDirectory, // 21
SYS_setWorkingDirectory, // 22
SYS_managePipe, // 23
SYS_readDir, // 24
SYS_getUptimeMilliseconds, // 25
SYS_sleepMilliseconds, // 26
SYS_executeOnTTY, // 27
SYS_manageMessage, // 28
SYS_UNUSED, // 29
SYS_mmap, // 30
SYS_munmap, // 31
SYS_shm_open, // 32
SYS_shm_unlink, // 33
SYS_ftruncate, // 34
SYS_posix_openpt, // 35
SYS_ptsname_r, // 36
SYSCALL_COUNT // 37
};
#endif // SYSCALLTABLE_H

344
kernel.soso/systemfs.c Normal file
View File

@ -0,0 +1,344 @@
#include "systemfs.h"
#include "common.h"
#include "fs.h"
#include "alloc.h"
#include "device.h"
#include "screen.h"
#include "vmm.h"
#include "process.h"
static FileSystemNode* gSystemFsRoot = NULL;
static BOOL systemfs_open(File *file, uint32 flags);
static FileSystemDirent *systemfs_readdir(FileSystemNode *node, uint32 index);
static FileSystemNode *systemfs_finddir(FileSystemNode *node, char *name);
static void createNodes();
static FileSystemDirent gDirent;
static int32 systemfs_read_meminfo_totalpages(File *file, uint32 size, uint8 *buffer);
static int32 systemfs_read_meminfo_usedpages(File *file, uint32 size, uint8 *buffer);
static BOOL systemfs_open_threads_dir(File *file, uint32 flags);
static void systemfs_close_threads_dir(File *file);
void initializeSystemFS()
{
gSystemFsRoot = kmalloc(sizeof(FileSystemNode));
memset((uint8*)gSystemFsRoot, 0, sizeof(FileSystemNode));
gSystemFsRoot->nodeType = FT_Directory;
FileSystemNode* rootFs = getFileSystemRootNode();
mkdir_fs(rootFs, "system", 0);
FileSystemNode* systemNode = finddir_fs(rootFs, "system");
if (systemNode)
{
systemNode->nodeType |= FT_MountPoint;
systemNode->mountPoint = gSystemFsRoot;
gSystemFsRoot->parent = systemNode->parent;
strcpy(gSystemFsRoot->name, systemNode->name);
}
else
{
PANIC("Could not create /system !");
}
gSystemFsRoot->open = systemfs_open;
gSystemFsRoot->finddir = systemfs_finddir;
gSystemFsRoot->readdir = systemfs_readdir;
createNodes();
}
static void createNodes()
{
FileSystemNode* nodeMemInfo = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodeMemInfo, 0, sizeof(FileSystemNode));
strcpy(nodeMemInfo->name, "meminfo");
nodeMemInfo->nodeType = FT_Directory;
nodeMemInfo->open = systemfs_open;
nodeMemInfo->finddir = systemfs_finddir;
nodeMemInfo->readdir = systemfs_readdir;
nodeMemInfo->parent = gSystemFsRoot;
gSystemFsRoot->firstChild = nodeMemInfo;
FileSystemNode* nodeMemInfoTotalPages = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodeMemInfoTotalPages, 0, sizeof(FileSystemNode));
strcpy(nodeMemInfoTotalPages->name, "totalpages");
nodeMemInfoTotalPages->nodeType = FT_File;
nodeMemInfoTotalPages->open = systemfs_open;
nodeMemInfoTotalPages->read = systemfs_read_meminfo_totalpages;
nodeMemInfoTotalPages->parent = nodeMemInfo;
nodeMemInfo->firstChild = nodeMemInfoTotalPages;
FileSystemNode* nodeMemInfoUsedPages = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodeMemInfoUsedPages, 0, sizeof(FileSystemNode));
strcpy(nodeMemInfoUsedPages->name, "usedpages");
nodeMemInfoUsedPages->nodeType = FT_File;
nodeMemInfoUsedPages->open = systemfs_open;
nodeMemInfoUsedPages->read = systemfs_read_meminfo_usedpages;
nodeMemInfoUsedPages->parent = nodeMemInfo;
nodeMemInfoTotalPages->nextSibling = nodeMemInfoUsedPages;
//
FileSystemNode* nodeThreads = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodeThreads, 0, sizeof(FileSystemNode));
strcpy(nodeThreads->name, "threads");
nodeThreads->nodeType = FT_Directory;
nodeThreads->open = systemfs_open_threads_dir;
nodeThreads->close = systemfs_close_threads_dir;
nodeThreads->finddir = systemfs_finddir;
nodeThreads->readdir = systemfs_readdir;
nodeThreads->parent = gSystemFsRoot;
nodeMemInfo->nextSibling = nodeThreads;
//
FileSystemNode* nodePipes = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodePipes, 0, sizeof(FileSystemNode));
strcpy(nodePipes->name, "pipes");
nodePipes->nodeType = FT_Directory;
nodePipes->parent = gSystemFsRoot;
nodeThreads->nextSibling = nodePipes;
//
FileSystemNode* nodeShm = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodeShm, 0, sizeof(FileSystemNode));
strcpy(nodeShm->name, "shm");
nodeShm->nodeType = FT_Directory;
nodeShm->parent = gSystemFsRoot;
nodePipes->nextSibling = nodeShm;
}
static BOOL systemfs_open(File *file, uint32 flags)
{
return TRUE;
}
static FileSystemDirent *systemfs_readdir(FileSystemNode *node, uint32 index)
{
int counter = 0;
FileSystemNode* child = node->firstChild;
//Screen_PrintF("systemfs_readdir-main:%s index:%d\n", node->name, index);
while (NULL != child)
{
//Screen_PrintF("systemfs_readdir-child:%s\n", child->name);
if (counter == index)
{
strcpy(gDirent.name, child->name);
gDirent.fileType = child->nodeType;
return &gDirent;
}
++counter;
child = child->nextSibling;
}
return NULL;
}
static FileSystemNode *systemfs_finddir(FileSystemNode *node, char *name)
{
//Screen_PrintF("systemfs_finddir-main:%s requestedName:%s\n", node->name, name);
FileSystemNode* child = node->firstChild;
while (NULL != child)
{
if (strcmp(name, child->name) == 0)
{
//Screen_PrintF("systemfs_finddir-found:%s\n", name);
return child;
}
child = child->nextSibling;
}
return NULL;
}
static int32 systemfs_read_meminfo_totalpages(File *file, uint32 size, uint8 *buffer)
{
if (size >= 4)
{
if (file->offset == 0)
{
int totalPages = getTotalPageCount();
sprintf((char*)buffer, "%d", totalPages);
int len = strlen((char*)buffer);
file->offset += len;
return len;
}
else
{
return 0;
}
}
return -1;
}
static int32 systemfs_read_meminfo_usedpages(File *file, uint32 size, uint8 *buffer)
{
if (size >= 4)
{
if (file->offset == 0)
{
int usedPages = getUsedPageCount();
sprintf((char*)buffer, "%d", usedPages);
int len = strlen((char*)buffer);
file->offset += len;
return len;
}
else
{
return 0;
}
}
return -1;
}
static BOOL systemfs_open_thread_file(File *file, uint32 flags)
{
return TRUE;
}
static void systemfs_close_thread_file(File *file)
{
}
static int32 systemfs_read_thread_file(File *file, uint32 size, uint8 *buffer)
{
if (size >= 128)
{
if (file->offset == 0)
{
int threadId = atoi(file->node->name);
Thread* thread = getThreadById(threadId);
if (thread)
{
int charIndex = 0;
charIndex += sprintf((char*)buffer + charIndex, "tid:%d\n", thread->threadId);
charIndex += sprintf((char*)buffer + charIndex, "userMode:%d\n", thread->userMode);
uint8 state[10];
threadStateToString(thread->state, state, 10);
charIndex += sprintf((char*)buffer + charIndex, "state:%s\n", state);
charIndex += sprintf((char*)buffer + charIndex, "contextSwitches:%d\n", thread->totalContextSwitchCount);
if (thread->owner)
{
charIndex += sprintf((char*)buffer + charIndex, "process:%d\n", thread->owner->pid);
}
else
{
charIndex += sprintf((char*)buffer + charIndex, "process:-\n");
}
int len = charIndex;
file->offset += len;
return len;
}
}
else
{
return 0;
}
}
return -1;
}
static void cleanThreadNodes(File *file)
{
FileSystemNode* node = file->node->firstChild;
while (node)
{
FileSystemNode* next = node->nextSibling;
kfree(node);
node = next;
}
}
static BOOL systemfs_open_threads_dir(File *file, uint32 flags)
{
char buffer[16];
cleanThreadNodes(file);
//And fill again
FileSystemNode* nodePrevious = NULL;
Thread* thread = getMainKernelThread();
while (NULL != thread)
{
FileSystemNode* nodeThread = kmalloc(sizeof(FileSystemNode));
memset((uint8*)nodeThread, 0, sizeof(FileSystemNode));
sprintf(buffer, "%d", thread->threadId);
strcpy(nodeThread->name, buffer);
nodeThread->nodeType = FT_File;
nodeThread->open = systemfs_open_thread_file;
nodeThread->close = systemfs_close_thread_file;
nodeThread->read = systemfs_read_thread_file;
nodeThread->finddir = systemfs_finddir;
nodeThread->readdir = systemfs_readdir;
nodeThread->parent = file->node;
if (nodePrevious)
{
nodePrevious->nextSibling = nodeThread;
}
else
{
file->node->firstChild = nodeThread;
}
nodePrevious = nodeThread;
thread = thread->next;
}
return TRUE;
}
static void systemfs_close_threads_dir(File *file)
{
//left blank intentionally
}

10
kernel.soso/systemfs.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef SYSTEMFS_H
#define SYSTEMFS_H
#include "device.h"
#include "fs.h"
#include "common.h"
void initializeSystemFS();
#endif // SYSTEMFS_H

39
kernel.soso/task.asm Normal file
View File

@ -0,0 +1,39 @@
global switchTask
switchTask:
mov esi, [esp]
pop eax ; *current thread
; get values from thread->regs structure
push dword [esi+4] ; eax
push dword [esi+8] ; ecx
push dword [esi+12] ; edx
push dword [esi+16] ; ebx
push dword [esi+24] ; ebp
push dword [esi+28] ; esi
push dword [esi+32] ; edi
push dword [esi+48] ; ds
push dword [esi+50] ; es
push dword [esi+52] ; fs
push dword [esi+54] ; gs
mov al, 0x20
out 0x20, al
mov eax, [esi+56]
mov cr3, eax
pop gs
pop fs
pop es
pop ds
pop edi
pop esi
pop ebp
pop ebx
pop edx
pop ecx
pop eax
iret

192
kernel.soso/termios.h Normal file
View File

@ -0,0 +1,192 @@
#ifndef TERMIOS_H
#define TERMIOS_H
//This file will also be included by C library.
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#define NCCS 32
struct termios
{
tcflag_t c_iflag; // input mode flags
tcflag_t c_oflag; // output mode flags
tcflag_t c_cflag; // control mode flags
tcflag_t c_lflag; // local mode flags
cc_t c_line; // line discipline
cc_t c_cc[NCCS]; // control characters
speed_t c_ispeed; // input speed
speed_t c_ospeed; // output speed
};
// c_cc characters
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
// c_iflag bits
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IUCLC 0001000
#define IXON 0002000
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
#define IUTF8 0040000
// c_oflag bits
#define OPOST 0000001
#define OLCUC 0000002
#define ONLCR 0000004
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 0000100
#define OFDEL 0000200
#define NLDLY 0000400
#define NL0 0000000
#define NL1 0000400
#define CRDLY 0003000
#define CR0 0000000
#define CR1 0001000
#define CR2 0002000
#define CR3 0003000
#define TABDLY 0014000
#define TAB0 0000000
#define TAB1 0004000
#define TAB2 0010000
#define TAB3 0014000
#define BSDLY 0020000
#define BS0 0000000
#define BS1 0020000
#define FFDLY 0100000
#define FF0 0000000
#define FF1 0100000
#define VTDLY 0040000
#define VT0 0000000
#define VT1 0040000
#define XTABS 0014000
// c_cflag bit meaning
# define CBAUD 0010017
#define B0 0000000 // hang up
#define B50 0000001
#define B75 0000002
#define B110 0000003
#define B134 0000004
#define B150 0000005
#define B200 0000006
#define B300 0000007
#define B600 0000010
#define B1200 0000011
#define B1800 0000012
#define B2400 0000013
#define B4800 0000014
#define B9600 0000015
#define B19200 0000016
#define B38400 0000017
#define EXTA B19200
#define EXTB B38400
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define B460800 0010004
#define B500000 0010005
#define B576000 0010006
#define B921600 0010007
#define B1000000 0010010
#define B1152000 0010011
#define B1500000 0010012
#define B2000000 0010013
#define B2500000 0010014
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
#define __MAX_BAUD B4000000
#define CIBAUD 002003600000 // input baud rate (not used)
#define CMSPAR 010000000000 // mark or space (stick) parity
#define CRTSCTS 020000000000 // flow control
// c_lflag bits
#define ISIG 0000001
#define ICANON 0000002
#define XCASE 0000004
#define ECHO 0000010
#define ECHOE 0000020
#define ECHOK 0000040
#define ECHONL 0000100
#define NOFLSH 0000200
#define TOSTOP 0000400
#define ECHOCTL 0001000
#define ECHOPRT 0002000
#define ECHOKE 0004000
#define FLUSHO 0010000
#define PENDIN 0040000
#define IEXTEN 0100000
#define EXTPROC 0200000
// tcflow() and TCXONC use these
#define TCOOFF 0
#define TCOON 1
#define TCIOFF 2
#define TCION 3
// tcflush() and TCFLSH use these
#define TCIFLUSH 0
#define TCOFLUSH 1
#define TCIOFLUSH 2
// tcsetattr uses these
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
//ioctl interface
#define TCGETS 0x5001
#define TCSETS 0x5002
#define TCSETSW 0x5003
#define TCSETSF 0x5004
#endif // TERMIOS_H

65
kernel.soso/timer.c Normal file
View File

@ -0,0 +1,65 @@
#include "timer.h"
#include "isr.h"
#include "screen.h"
#include "process.h"
#include "common.h"
#define TIMER_FREQ 1000
uint32 gSystemTickCount = 0;
BOOL gSchedulerEnabled = FALSE;
//called from assembly
void handleTimerIRQ(TimerInt_Registers registers)
{
gSystemTickCount++;
if (/*gSystemTickCount % 10 == 0 &&*/ gSchedulerEnabled == TRUE)
{
schedule(&registers);
}
}
uint32 getSystemTickCount()
{
return gSystemTickCount;
}
uint32 getUptimeSeconds()
{
return gSystemTickCount / TIMER_FREQ;
}
uint32 getUptimeMilliseconds()
{
return gSystemTickCount;
}
void enableScheduler()
{
gSchedulerEnabled = TRUE;
}
void disableScheduler()
{
gSchedulerEnabled = FALSE;
}
static void initTimer(uint32 frequency)
{
uint32 divisor = 1193180 / frequency;
outb(0x43, 0x36);
uint8 l = (uint8)(divisor & 0xFF);
uint8 h = (uint8)( (divisor>>8) & 0xFF );
outb(0x40, l);
outb(0x40, h);
}
void initializeTimer()
{
initTimer(TIMER_FREQ);
}

13
kernel.soso/timer.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef TIMER_H
#define TIMER_H
#include "common.h"
void initializeTimer();
uint32 getSystemTickCount();
uint32 getUptimeSeconds();
uint32 getUptimeMilliseconds();
void enableScheduler();
void disableScheduler();
#endif

175
kernel.soso/tty.c Normal file
View File

@ -0,0 +1,175 @@
#include "tty.h"
#include "alloc.h"
Tty* createTty(uint16 lineCount, uint16 columnCount, TtyFlushScreenFunction flushFunction)
{
Tty* tty = kmalloc(sizeof(Tty));
memset((uint8*)tty, 0, sizeof(Tty));
tty->lineCount = lineCount;
tty->columnCount = columnCount;
tty->buffer = kmalloc(tty->lineCount * tty->columnCount * 2);
tty->currentColumn = 0;
tty->currentLine = 0;
tty->color = 0x0A;
memset(tty->lineBuffer, 0, TTY_LINEBUFFER_SIZE);
tty->lineBufferIndex = 0;
tty->keyBuffer = FifoBuffer_create(64);
tty->flushScreen = flushFunction;
tty->term.c_cc[VMIN] = 1;
tty->term.c_lflag |= ECHO;
tty->term.c_lflag |= ICANON;
Tty_Clear(tty);
return tty;
}
void destroyTty(Tty* tty)
{
FifoBuffer_destroy(tty->keyBuffer);
kfree(tty->buffer);
kfree(tty);
}
void Tty_Print(Tty* tty, int row, int column, const char* text)
{
unsigned char * video = tty->buffer;
video += (row * tty->columnCount + column) * 2;
while(*text != 0)
{
*video++ = *text++;
*video++ = tty->color;
}
}
//One line
void Tty_ScrollUp(Tty* tty)
{
unsigned char * videoLine = tty->buffer;
unsigned char * videoLineNext = tty->buffer;
int line = 0;
int column = 0;
for (line = 0; line < tty->lineCount - 1; ++line)
{
for (column = 0; column < tty->columnCount; ++column)
{
videoLine = tty->buffer + (line * tty->columnCount + column) * 2;
videoLineNext = tty->buffer + ((line + 1) * tty->columnCount + column) * 2;
videoLine[0] = videoLineNext[0];
videoLine[1] = videoLineNext[1];
}
}
//Last line should be empty.
unsigned char * lastLine = tty->buffer + ((tty->lineCount - 1) * tty->columnCount) * 2;
for (int i = 0; i < tty->columnCount * 2; i += 2)
{
lastLine[i] = 0;
lastLine[i + 1] = tty->color;
}
}
void Tty_Clear(Tty* tty)
{
unsigned char * video = tty->buffer;
int i = 0;
for (i = 0; i < tty->lineCount * tty->columnCount; ++i)
{
*video++ = 0;
*video++ = tty->color;
}
tty->currentLine = 0;
tty->currentColumn = 0;
}
void Tty_PutChar(Tty* tty, char c)
{
unsigned char * video = tty->buffer;
if ('\n' == c || '\r' == c)
{
++tty->currentLine;
tty->currentColumn = 0;
if (tty->currentLine >= tty->lineCount - 0)
{
--tty->currentLine;
Tty_ScrollUp(tty);
}
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
return;
}
else if ('\b' == c)
{
if (tty->currentColumn > 0)
{
--tty->currentColumn;
c = '\0';
video = tty->buffer + (tty->currentLine * tty->columnCount + tty->currentColumn) * 2;
video[0] = c;
video[1] = tty->color;
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
return;
}
else if (tty->currentColumn == 0)
{
if (tty->currentLine > 0)
{
--tty->currentLine;
tty->currentColumn = tty->columnCount - 1;
c = '\0';
video = tty->buffer + (tty->currentLine * tty->columnCount + tty->currentColumn) * 2;
video[0] = c;
video[1] = tty->color;
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
return;
}
}
}
if (tty->currentColumn >= tty->columnCount)
{
++tty->currentLine;
tty->currentColumn = 0;
}
if (tty->currentLine >= tty->lineCount - 0)
{
--tty->currentLine;
Tty_ScrollUp(tty);
}
video += (tty->currentLine * tty->columnCount + tty->currentColumn) * 2;
video[0] = c;
video[1] = tty->color;
++tty->currentColumn;
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
}
void Tty_PutText(Tty* tty, const char* text)
{
const char* c = text;
while (*c)
{
Tty_PutChar(tty, *c);
++c;
}
}
void Tty_MoveCursor(Tty* tty, uint16 line, uint16 column)
{
tty->currentLine = line;
tty->currentColumn = column;
}

42
kernel.soso/tty.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef TTY_H
#define TTY_H
#include "common.h"
#include "fifobuffer.h"
#include "termios.h"
#define TTY_LINEBUFFER_SIZE 1024
typedef struct Tty Tty;
typedef void (*TtyFlushScreenFunction)(Tty* tty);
typedef struct Tty
{
uint16 lineCount;
uint16 columnCount;
uint8* buffer;
uint16 currentLine;
uint16 currentColumn;
uint8 color;
void* privateData;
uint8 lineBuffer[TTY_LINEBUFFER_SIZE];
uint32 lineBufferIndex;
FifoBuffer* keyBuffer;
struct termios term;
TtyFlushScreenFunction flushScreen;
} Tty;
Tty* createTty(uint16 lineCount, uint16 columnCount, TtyFlushScreenFunction flushFunction);
void destroyTty(Tty* tty);
void Tty_Print(Tty* tty, int row, int column, const char* text);
void Tty_Clear(Tty* tty);
void Tty_PutChar(Tty* tty, char c);
void Tty_PutText(Tty* tty, const char* text);
void Tty_MoveCursor(Tty* tty, uint16 line, uint16 column);
void Tty_ScrollUp(Tty* tty);
#endif // TTY_H

671
kernel.soso/ttydriver.c Normal file
View File

@ -0,0 +1,671 @@
#include "ttydriver.h"
#include "device.h"
#include "screen.h"
#include "serial.h"
#include "devfs.h"
#include "alloc.h"
#include "common.h"
#include "list.h"
#include "fifobuffer.h"
#include "gfx.h"
#include "debugprint.h"
#include "commonuser.h"
#include "termios.h"
static List* gTtyList = NULL;
static List* gReaderList = NULL;
static Tty* gActiveTty = NULL;
static uint8 gKeyModifier = 0;
static uint32 gPseudoTerminalNameGenerator = 0;
typedef enum KeyModifier
{
KM_LeftShift = 1,
KM_RightShift = 2,
KM_Ctrl = 4,
KM_Alt = 8
} KeyModifier;
enum
{
KEY_LEFTSHIFT = 0x2A,
KEY_RIGHTSHIFT = 0x36,
KEY_CTRL = 0x1D,
KEY_ALT = 0x38,
KEY_CAPSLOCK = 0x3A,
KEY_F1 = 0x3B,
KEY_F2 = 0x3C,
KEY_F3 = 0x3D
};
// PC keyboard interface constants
#define KBSTATP 0x64 // kbd controller status port(I)
#define KBS_DIB 0x01 // kbd data in buffer
#define KBDATAP 0x60 // kbd data port(I)
#define NO 0
#define SHIFT (1<<0)
#define CTL (1<<1)
#define ALT (1<<2)
#define CAPSLOCK (1<<3)
#define NUMLOCK (1<<4)
#define SCROLLLOCK (1<<5)
#define E0ESC (1<<6)
// Special keycodes
#define KEY_HOME 0xE0
#define KEY_END 0xE1
#define KEY_UP 0xE2
#define KEY_DOWN 0xE3
#define KEY_LEFT 0xE4
#define KEY_RIGHT 0xE5
#define KEY_PAGEUP 0xE6
#define KEY_PAGEDOWN 0xE7
#define KEY_INSERT 0xE8
#define KEY_DELETE 0xE9
// C('A') == Control-A
#define C(x) (x - '@')
static uint8 gKeyMap[256] =
{
NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00
'7', '8', '9', '0', '-', '=', '\b', '\t',
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10
'o', 'p', '[', ']', '\n', NO, 'a', 's',
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20
'\'', '`', NO, '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30
NO, ' ', NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
'8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
[0x49] = KEY_PAGEUP,
[0x51] = KEY_PAGEDOWN,
[0x47] = KEY_HOME,
[0x4F] = KEY_END,
[0x52] = KEY_INSERT,
[0x53] = KEY_DELETE,
[0x48] = KEY_UP,
[0x50] = KEY_DOWN,
[0x4B] = KEY_LEFT,
[0x4D] = KEY_RIGHT,
[0x9C] = '\n', // KP_Enter
[0xB5] = '/', // KP_Div
[0xC8] = KEY_UP,
[0xD0] = KEY_DOWN,
[0xC9] = KEY_PAGEUP,
[0xD1] = KEY_PAGEDOWN,
[0xCB] = KEY_LEFT,
[0xCD] = KEY_RIGHT,
[0x97] = KEY_HOME,
[0xCF] = KEY_END,
[0xD2] = KEY_INSERT,
[0xD3] = KEY_DELETE
};
static uint8 gKeyShiftMap[256] =
{
NO, 033, '!', '@', '#', '$', '%', '^', // 0x00
'&', '*', '(', ')', '_', '+', '\b', '\t',
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10
'O', 'P', '{', '}', '\n', NO, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20
'"', '~', NO, '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30
NO, ' ', NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
'8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
[0x49] = KEY_PAGEUP,
[0x51] = KEY_PAGEDOWN,
[0x47] = KEY_HOME,
[0x4F] = KEY_END,
[0x52] = KEY_INSERT,
[0x53] = KEY_DELETE,
[0x48] = KEY_UP,
[0x50] = KEY_DOWN,
[0x4B] = KEY_LEFT,
[0x4D] = KEY_RIGHT,
[0x9C] = '\n', // KP_Enter
[0xB5] = '/', // KP_Div
[0xC8] = KEY_UP,
[0xD0] = KEY_DOWN,
[0xC9] = KEY_PAGEUP,
[0xD1] = KEY_PAGEDOWN,
[0xCB] = KEY_LEFT,
[0xCD] = KEY_RIGHT,
[0x97] = KEY_HOME,
[0xCF] = KEY_END,
[0xD2] = KEY_INSERT,
[0xD3] = KEY_DELETE
};
static BOOL tty_open(File *file, uint32 flags);
static void tty_close(File *file);
static int32 tty_ioctl(File *file, int32 request, void * argp);
static int32 tty_read(File *file, uint32 size, uint8 *buffer);
static int32 tty_write(File *file, uint32 size, uint8 *buffer);
static int32 write(Tty* tty, uint32 size, uint8 *buffer);
static uint8 getCharacterForScancode(KeyModifier modifier, uint8 scancode);
static void processScancode(uint8 scancode);
void initializeTTYs(BOOL graphicMode)
{
gTtyList = List_Create();
gReaderList = List_Create();
for (int i = 1; i <= 9; ++i)
{
Tty* tty = NULL;
if (graphicMode)
{
tty = createTty(768 / 16, 1024 / 9, Gfx_FlushFromTty);
}
else
{
tty = createTty(25, 80, Screen_FlushFromTty);
}
tty->color = 0x0A;
List_Append(gTtyList, tty);
Device device;
memset((uint8*)&device, 0, sizeof(Device));
sprintf(device.name, "tty%d", i);
device.deviceType = FT_CharacterDevice;
device.open = tty_open;
device.close = tty_close;
device.ioctl = tty_ioctl;
device.read = tty_read;
device.write = tty_write;
device.privateData = tty;
registerDevice(&device);
}
gActiveTty = List_GetFirstNode(gTtyList)->data;
}
Tty* getActiveTTY()
{
return gActiveTty;
}
FileSystemNode* createPseudoTerminal()
{
Tty* tty = createTty(768 / 16, 1024 / 9, Gfx_FlushFromTty);
tty->color = 0x0A;
Device device;
memset((uint8*)&device, 0, sizeof(Device));
sprintf(device.name, "pts%d", gPseudoTerminalNameGenerator++);
device.deviceType = FT_CharacterDevice;
device.open = tty_open;
device.close = tty_close;
device.ioctl = tty_ioctl;
device.read = tty_read;
device.write = tty_write;
device.privateData = tty;
FileSystemNode* node = registerDevice(&device);
if (NULL == node)
{
destroyTty(tty);
}
return node;
}
static void sendInputToKeyBuffer(Tty* tty, uint8 scancode, uint8 character)
{
char seq[8];
memset(seq, 0, 8);
switch (character) {
case KEY_PAGEUP:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 53;
seq[3] = 126;
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
}
break;
case KEY_PAGEDOWN:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 54;
seq[3] = 126;
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
}
break;
case KEY_HOME:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 72;
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
}
break;
case KEY_END:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 70;
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
}
break;
case KEY_INSERT:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 50;
seq[3] = 126;
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
}
break;
case KEY_DELETE:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 51;
seq[3] = 126;
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
}
break;
case KEY_UP:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 65;
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
}
break;
case KEY_DOWN:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 66;
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
}
break;
case KEY_RIGHT:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 67;
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
}
break;
case KEY_LEFT:
{
seq[0] = 27;
seq[1] = 91;
seq[2] = 68;
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
}
break;
default:
FifoBuffer_enqueue(tty->keyBuffer, &character, 1);
break;
}
}
void sendKeyInputToTTY(Tty* tty, uint8 scancode)
{
beginCriticalSection();
processScancode(scancode);
uint8 character = getCharacterForScancode(gKeyModifier, scancode);
uint8 keyRelease = (0x80 & scancode); //ignore release event
if (character > 0 && keyRelease == 0)
{
//enqueue for non-canonical readers
sendInputToKeyBuffer(tty, scancode, character);
//FifoBuffer_enqueue(tty->keyBuffer, &scancode, 1);
if (tty->lineBufferIndex >= TTY_LINEBUFFER_SIZE - 1)
{
tty->lineBufferIndex = 0;
}
if (character == '\b')
{
if (tty->lineBufferIndex > 0)
{
tty->lineBuffer[--tty->lineBufferIndex] = '\0';
if ((tty->term.c_lflag & ECHO) == ECHO)
{
write(tty, 1, &character);
}
}
}
else
{
tty->lineBuffer[tty->lineBufferIndex++] = character;
if ((tty->term.c_lflag & ECHO) == ECHO)
{
write(tty, 1, &character);
}
}
}
//Wake readers
List_Foreach(n, gReaderList)
{
File* file = n->data;
if (file->thread->state == TS_WAITIO)
{
if (file->thread->state_privateData == tty)
{
file->thread->state = TS_RUN;
file->thread->state_privateData = NULL;
}
}
}
endCriticalSection();
}
static BOOL tty_open(File *file, uint32 flags)
{
//Screen_PrintF("tty_open: pid:%d\n", file->process->pid);
Tty* tty = (Tty*)file->node->privateNodeData;
FifoBuffer_clear(tty->keyBuffer);
List_Append(gReaderList, file);
return TRUE;
}
static void tty_close(File *file)
{
List_RemoveFirstOccurrence(gReaderList, file);
}
static int32 tty_ioctl(File *file, int32 request, void * argp)
{
Tty* tty = (Tty*)file->node->privateNodeData;
switch (request)
{
case 0:
{
sendKeyInputToTTY(tty, (uint8)(uint32)argp);
return 0;
}
break;
case 1:
return tty->columnCount * tty->lineCount * 2;
break;
case 2:
{
//set
TtyUserBuffer* userTtyBuffer = (TtyUserBuffer*)argp;
memcpy(tty->buffer, (uint8*)userTtyBuffer->buffer, tty->columnCount * tty->lineCount * 2);
return 0;
}
break;
case 3:
{
//get
TtyUserBuffer* userTtyBuffer = (TtyUserBuffer*)argp;
userTtyBuffer->columnCount = tty->columnCount;
userTtyBuffer->lineCount = tty->lineCount;
userTtyBuffer->currentColumn = tty->currentColumn;
userTtyBuffer->currentLine = tty->currentLine;
memcpy((uint8*)userTtyBuffer->buffer, tty->buffer, tty->columnCount * tty->lineCount * 2);
return 0;
}
break;
case TCGETS:
{
struct termios* term = (struct termios*)argp;
//Debug_PrintF("TCGETS\n");
memcpy((uint8*)term, (uint8*)&(tty->term), sizeof(struct termios));
return 0;//success
}
break;
case TCSETS:
case TCSETSW:
break;
case TCSETSF:
{
struct termios* term = (struct termios*)argp;
//Debug_PrintF("TCSETSF\n");
memcpy((uint8*)&(tty->term), (uint8*)term, sizeof(struct termios));
return 0;//success
}
break;
default:
break;
}
return -1;
}
static int32 tty_read(File *file, uint32 size, uint8 *buffer)
{
enableInterrupts();
if (size > 0)
{
Tty* tty = (Tty*)file->node->privateNodeData;
if ((tty->term.c_lflag & ICANON) == ICANON)
{
while (TRUE)
{
for (int i = 0; i < tty->lineBufferIndex; ++i)
{
char chr = tty->lineBuffer[i];
if (chr == '\n')
{
int bytesToCopy = MIN(tty->lineBufferIndex, size);
if (bytesToCopy >= tty->term.c_cc[VMIN])
{
tty->lineBufferIndex = 0;
memcpy(buffer, tty->lineBuffer, bytesToCopy);
return bytesToCopy;
}
}
}
file->thread->state = TS_WAITIO;
file->thread->state_privateData = tty;
halt();
}
}
else
{
while (TRUE)
{
uint32 neededSize = tty->term.c_cc[VMIN];
uint32 bufferLen = FifoBuffer_getSize(tty->keyBuffer);
if (bufferLen >= neededSize)
{
int readSize = FifoBuffer_dequeue(tty->keyBuffer, buffer, MIN(bufferLen, size));
return readSize;
}
file->thread->state = TS_WAITIO;
file->thread->state_privateData = tty;
halt();
}
}
}
return -1;
}
static int32 write(Tty* tty, uint32 size, uint8 *buffer)
{
buffer[size] = '\0';
Tty_PutText(tty, (const char*)buffer);
if (gActiveTty == tty)
{
if (gActiveTty->flushScreen)
{
gActiveTty->flushScreen(gActiveTty);
}
}
return size;
}
static int32 tty_write(File *file, uint32 size, uint8 *buffer)
{
return write(file->node->privateNodeData, size, buffer);
}
static void setActiveTty(Tty* tty)
{
gActiveTty = tty;
Gfx_Fill(0xFFFFFFFF);
if (tty->flushScreen)
{
tty->flushScreen(tty);
}
//Serial_PrintF("line:%d column:%d\r\n", gActiveTty->currentLine, gActiveTty->currentColumn);
}
BOOL isValidTTY(Tty* tty)
{
List_Foreach(n, gTtyList)
{
if (n->data == tty)
{
return TRUE;
}
}
return FALSE;
}
static uint8 getCharacterForScancode(KeyModifier modifier, uint8 scancode)
{
//return gKeyboardLayout[scancode];
if ((modifier & KM_LeftShift) == KM_LeftShift || (modifier & KM_RightShift) == KM_RightShift)
{
return gKeyShiftMap[scancode];
}
return gKeyMap[scancode];
}
static void applyModifierKeys(KeyModifier modifier, uint8 scancode)
{
if ((modifier & KM_Ctrl) == KM_Ctrl)
{
int ttyIndex = scancode - KEY_F1;
//printkf("TTY:%d\n", ttyIndex);
int ttyCount = List_GetCount(gTtyList);
if (ttyIndex >= 0 && ttyIndex < ttyCount)
{
int i = 0;
List_Foreach(n, gTtyList)
{
if (ttyIndex == i)
{
setActiveTty(n->data);
break;
}
++i;
}
}
}
}
static void processScancode(uint8 scancode)
{
uint8 lastBit = scancode & 0x80;
scancode &= 0x7F;
if (lastBit)
{
//key release
switch (scancode)
{
case KEY_LEFTSHIFT:
gKeyModifier &= ~KM_LeftShift;
break;
case KEY_RIGHTSHIFT:
gKeyModifier &= ~KM_RightShift;
break;
case KEY_CTRL:
gKeyModifier &= ~KM_Ctrl;
break;
case KEY_ALT:
gKeyModifier &= ~KM_Alt;
break;
}
//Screen_PrintF("released: %x (%d)\n", scancode, scancode);
}
else
{
//key pressed
switch (scancode)
{
case KEY_LEFTSHIFT:
gKeyModifier |= KM_LeftShift;
break;
case KEY_RIGHTSHIFT:
gKeyModifier |= KM_RightShift;
break;
case KEY_CTRL:
gKeyModifier |= KM_Ctrl;
break;
case KEY_ALT:
gKeyModifier |= KM_Alt;
break;
}
//Screen_PrintF("pressed: %x (%d)\n", scancode, scancode);
applyModifierKeys(gKeyModifier, scancode);
}
}

17
kernel.soso/ttydriver.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef TTYDRIVER_H
#define TTYDRIVER_H
#include "common.h"
#include "tty.h"
#include "fs.h"
void initializeTTYs(BOOL graphicMode);
Tty* getActiveTTY();
void sendKeyInputToTTY(Tty* tty, uint8 scancode);
BOOL isValidTTY(Tty* tty);
FileSystemNode* createPseudoTerminal();
#endif // TTYDRIVER_H

18
kernel.soso/utils.asm Normal file
View File

@ -0,0 +1,18 @@
[GLOBAL readEip]
readEip:
pop eax
jmp eax
[GLOBAL disablePaging]
disablePaging:
mov edx, cr0
and edx, 0x7fffffff
mov cr0, edx
ret
[GLOBAL enablePaging]
enablePaging:
mov edx, cr0
or edx, 0x80000000
mov cr0, edx
ret

63
kernel.soso/vbe.h Normal file
View File

@ -0,0 +1,63 @@
#ifndef VBE_H
#define VBE_H
typedef struct {
/* Mandatory information for all VBE revisions */
uint16 ModeAttributes; /**< @brief mode attributes */
uint8 WinAAttributes; /**< @brief window A attributes */
uint8 WinBAttributes; /**< @brief window B attributes */
uint16 WinGranularity; /**< @brief window granularity */
uint16 WinSize; /**< @brief window size */
uint16 WinASegment; /**< @brief window A start segment */
uint16 WinBSegment; /**< @brief window B start segment */
void* WinFuncPtr; /**< @brief real mode/far pointer to window function */
uint16 BytesPerScanLine; /**< @brief bytes per scan line */
/* Mandatory information for VBE 1.2 and above */
uint16 XResolution; /**< @brief horizontal resolution in pixels/characters */
uint16 YResolution; /**< @brief vertical resolution in pixels/characters */
uint8 XCharSize; /**< @brief character cell width in pixels */
uint8 YCharSize; /**< @brief character cell height in pixels */
uint8 NumberOfPlanes; /**< @brief number of memory planes */
uint8 BitsPerPixel; /**< @brief bits per pixel */
uint8 NumberOfBanks; /**< @brief number of banks */
uint8 MemoryModel; /**< @brief memory model type */
uint8 BankSize; /**< @brief bank size in KB */
uint8 NumberOfImagePages; /**< @brief number of images */
uint8 Reserved1; /**< @brief reserved for page function */
/* Direct Color fields (required for direct/6 and YUV/7 memory models) */
uint8 RedMaskSize; /* size of direct color red mask in bits */
uint8 RedFieldPosition; /* bit position of lsb of red mask */
uint8 GreenMaskSize; /* size of direct color green mask in bits */
uint8 GreenFieldPosition; /* bit position of lsb of green mask */
uint8 BlueMaskSize; /* size of direct color blue mask in bits */
uint8 BlueFieldPosition; /* bit position of lsb of blue mask */
uint8 RsvdMaskSize; /* size of direct color reserved mask in bits */
uint8 RsvdFieldPosition; /* bit position of lsb of reserved mask */
uint8 DirectColorModeInfo; /* direct color mode attributes */
/* Mandatory information for VBE 2.0 and above */
void* PhysBasePtr; /**< @brief physical address for flat memory frame buffer */
uint8 Reserved2[4]; /**< @brief Reserved - always set to 0 */
uint8 Reserved3[2]; /**< @brief Reserved - always set to 0 */
/* Mandatory information for VBE 3.0 and above */
uint16 LinBytesPerScanLine; /* bytes per scan line for linear modes */
uint8 BnkNumberOfImagePages; /* number of images for banked modes */
uint8 LinNumberOfImagePages; /* number of images for linear modes */
uint8 LinRedMaskSize; /* size of direct color red mask (linear modes) */
uint8 LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */
uint8 LinGreenMaskSize; /* size of direct color green mask (linear modes) */
uint8 LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */
uint8 LinBlueMaskSize; /* size of direct color blue mask (linear modes) */
uint8 LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes ) */
uint8 LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */
uint8 LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */
uint32 MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */
uint8 Reserved4[190]; /* remainder of ModeInfoBlock */
} __attribute__((packed)) vbe_mode_info_t;
#endif // VBE_H

580
kernel.soso/vmm.c Normal file
View File

@ -0,0 +1,580 @@
#include "vmm.h"
#include "common.h"
#include "screen.h"
#include "alloc.h"
#include "isr.h"
#include "process.h"
#include "list.h"
#include "debugprint.h"
uint32 *gKernelPageDirectory = (uint32 *)KERN_PAGE_DIRECTORY;
uint8 gPhysicalPageFrameBitmap[RAM_AS_4M_PAGES / 8];
uint8 gKernelPageHeapBitmap[RAM_AS_4K_PAGES / 8];
static int gTotalPageCount = 0;
static void handlePageFault(Registers *regs);
static void syncPageDirectoriesKernelMemory();
void initializeMemory(uint32 high_mem)
{
int pg;
unsigned long i;
registerInterruptHandler(14, handlePageFault);
gTotalPageCount = (high_mem * 1024) / PAGESIZE_4M;
for (pg = 0; pg < gTotalPageCount / 8; ++pg)
{
gPhysicalPageFrameBitmap[pg] = 0;
}
for (pg = gTotalPageCount / 8; pg < RAM_AS_4M_PAGES / 8; ++pg)
{
gPhysicalPageFrameBitmap[pg] = 0xFF;
}
//Pages reserved for the kernel
for (pg = PAGE_INDEX_4M(0x0); pg < (int)(PAGE_INDEX_4M(RESERVED_AREA)); ++pg)
{
SET_PAGEFRAME_USED(gPhysicalPageFrameBitmap, pg);
}
//Heap pages reserved
for (pg = 0; pg < RAM_AS_4K_PAGES / 8; ++pg)
{
gKernelPageHeapBitmap[pg] = 0xFF;
}
for (pg = PAGE_INDEX_4K(KERN_PD_AREA_BEGIN); pg < (int)(PAGE_INDEX_4K(KERN_PD_AREA_END)); ++pg)
{
SET_PAGEHEAP_UNUSED(pg * PAGESIZE_4K);
}
//Identity map
for (i = 0; i < 4; ++i)
{
gKernelPageDirectory[i] = (i * PAGESIZE_4M | (PG_PRESENT | PG_WRITE | PG_4MB));//add PG_USER for accesing kernel code in user mode
}
for (i = 4; i < 1024; ++i)
{
gKernelPageDirectory[i] = 0;
}
//Enable paging
asm(" mov %0, %%eax \n \
mov %%eax, %%cr3 \n \
mov %%cr4, %%eax \n \
or %2, %%eax \n \
mov %%eax, %%cr4 \n \
mov %%cr0, %%eax \n \
or %1, %%eax \n \
mov %%eax, %%cr0"::"m"(gKernelPageDirectory), "i"(PAGING_FLAG), "i"(PSE_FLAG));
initializeKernelHeap();
}
char* getPageFrame4M()
{
int byte, bit;
uint32 page = -1;
for (byte = 0; byte < RAM_AS_4M_PAGES / 8; byte++)
{
if (gPhysicalPageFrameBitmap[byte] != 0xFF)
{
for (bit = 0; bit < 8; bit++)
{
if (!(gPhysicalPageFrameBitmap[byte] & (1 << bit)))
{
page = 8 * byte + bit;
SET_PAGEFRAME_USED(gPhysicalPageFrameBitmap, page);
Debug_PrintF("DEBUG: got 4M on physical %x\n", page * PAGESIZE_4M);
return (char *) (page * PAGESIZE_4M);
}
}
}
}
PANIC("Memory is full!");
return (char *) -1;
}
void releasePageFrame4M(uint32 p_addr)
{
Debug_PrintF("DEBUG: released 4M on physical %x\n", p_addr);
SET_PAGEFRAME_UNUSED(gPhysicalPageFrameBitmap, p_addr);
}
uint32* getPdFromReservedArea4K()
{
int byte, bit;
int page = -1;
//Screen_PrintF("DEBUG: getPdFromReservedArea4K() begin\n");
for (byte = 0; byte < RAM_AS_4K_PAGES / 8; byte++)
{
if (gKernelPageHeapBitmap[byte] != 0xFF)
{
for (bit = 0; bit < 8; bit++)
{
if (!(gKernelPageHeapBitmap[byte] & (1 << bit)))
{
page = 8 * byte + bit;
SET_PAGEHEAP_USED(page);
//Screen_PrintF("DEBUG: getPdFromReservedArea4K() found pageIndex:%d\n", page);
return (uint32 *) (page * PAGESIZE_4K);
}
}
}
}
PANIC("Reserved Page Directory Area is Full!!!");
return (uint32 *) -1;
}
void releasePdFromReservedArea4K(uint32 *v_addr)
{
SET_PAGEHEAP_UNUSED(v_addr);
}
uint32 *createPd()
{
int i;
uint32* pd = getPdFromReservedArea4K();
for (i = 0; i < KERNELMEMORY_PAGE_COUNT; ++i)
{
pd[i] = gKernelPageDirectory[i];
}
for (i = KERNELMEMORY_PAGE_COUNT; i < 1024; ++i)
{
pd[i] = 0;
}
return pd;
}
void destroyPd(uint32 *pd)
{
int startIndex = PAGE_INDEX_4M(USER_OFFSET);
int lastIndex = PAGE_INDEX_4M(USER_OFFSET_END);
///we don't touch mmapped areas
for (int i = startIndex; i < lastIndex; ++i)
{
uint32 p_addr = pd[i] & 0xFFC00000;
if (p_addr)
{
releasePageFrame4M(p_addr);
}
pd[i] = 0;
}
releasePdFromReservedArea4K(pd);
}
uint32 *copyPd(uint32* pd)
{
int i;
uint32* newPd = getPdFromReservedArea4K();
for (i = 0; i < KERNELMEMORY_PAGE_COUNT; ++i)
{
newPd[i] = gKernelPageDirectory[i];
}
disablePaging();
for (i = KERNELMEMORY_PAGE_COUNT; i < 1024; ++i)
{
newPd[i] = 0;
if ((pd[i] & PG_PRESENT) == PG_PRESENT)
{
uint32 pagePyhsical = pd[i] & 0xFFC00000;
char* newPagePhysical = getPageFrame4M();
memcpy((uint8*)newPagePhysical, (uint8*)pagePyhsical, PAGESIZE_4M);
uint32 vAddr = (i * 4) << 20;
//Screen_PrintF("Copied page virtual %x\n", vAddr);
addPageToPd(newPd, (char*)vAddr, newPagePhysical, PG_USER);
}
}
enablePaging();
return newPd;
}
//When calling this function:
//If it is intended to alloc kernel memory, v_addr must be < KERN_HEAP_END.
//If it is intended to alloc user memory, v_addr must be > KERN_HEAP_END.
BOOL addPageToPd(uint32* pd, char *v_addr, char *p_addr, int flags)
{
uint32 *pde = NULL;
//Screen_PrintF("DEBUG: addPageToPd(): v_addr:%x p_addr:%x flags:%x\n", v_addr, p_addr, flags);
int index = (((uint32) v_addr & 0xFFC00000) >> 22);
pde = pd + index;
if ((*pde & PG_PRESENT) == PG_PRESENT)
{
//Already assigned!
Debug_PrintF("ERROR: addPageToPd(): pde:%x is already assigned!!\n", pde);
return FALSE;
}
//Screen_PrintF("addPageToPd(): index:%d pde:%x\n", index, pde);
*pde = ((uint32) p_addr) | (PG_PRESENT | PG_4MB | PG_WRITE | flags);
//Screen_PrintF("pde:%x *pde:%x\n", pde, *pde);
SET_PAGEFRAME_USED(gPhysicalPageFrameBitmap, PAGE_INDEX_4M((uint32)p_addr));
asm("invlpg %0"::"m"(v_addr));
if (v_addr <= (char*)(KERN_HEAP_END - PAGESIZE_4M))
{
if (pd == gKernelPageDirectory)
{
syncPageDirectoriesKernelMemory();
}
else
{
PANIC("Attemped to allocate kernel memory to a page directory which is not the kernel page directory!!!\n");
}
}
else
{
if (pd == gKernelPageDirectory)
{
//No panic here. Because we allow kernel to map anywhere!
}
}
return TRUE;
}
BOOL removePageFromPd(uint32* pd, char *v_addr, BOOL releasePageFrame)
{
int index = (((uint32) v_addr & 0xFFC00000) >> 22);
uint32* pde = pd + index;
if ((*pde & PG_PRESENT) == PG_PRESENT)
{
uint32 p_addr = *pde & 0xFFC00000;
if (releasePageFrame)
{
releasePageFrame4M(p_addr);
}
*pde = 0;
asm("invlpg %0"::"m"(v_addr));
if (v_addr <= (char*)(KERN_HEAP_END - PAGESIZE_4M))
{
if (pd == gKernelPageDirectory)
{
syncPageDirectoriesKernelMemory();
}
}
return TRUE;
}
return FALSE;
}
static void syncPageDirectoriesKernelMemory()
{
//get page directory list
//it can be easier to traverse proccesses(and access its pd) here
for (int byte = 0; byte < RAM_AS_4M_PAGES / 8; byte++)
{
if (gKernelPageHeapBitmap[byte] != 0xFF)
{
for (int bit = 0; bit < 8; bit++)
{
if ((gKernelPageHeapBitmap[byte] & (1 << bit)))
{
int page = 8 * byte + bit;
uint32* pd = (uint32*)(page * PAGESIZE_4K);
for (int i = 0; i < KERNELMEMORY_PAGE_COUNT; ++i)
{
pd[i] = gKernelPageDirectory[i];
}
}
}
}
}
}
uint32 getTotalPageCount()
{
return gTotalPageCount;
}
uint32 getUsedPageCount()
{
int count = 0;
for (int i = 0; i < gTotalPageCount; ++i)
{
if(IS_PAGEFRAME_USED(gPhysicalPageFrameBitmap, i))
{
++count;
}
}
return count;
}
uint32 getFreePageCount()
{
return gTotalPageCount - getUsedPageCount();
}
static void printPageFaultInfo(uint32 faultingAddress, Registers *regs)
{
int present = regs->errorCode & 0x1;
int rw = regs->errorCode & 0x2;
int us = regs->errorCode & 0x4;
int reserved = regs->errorCode & 0x8;
int id = regs->errorCode & 0x10;
printkf("Page fault!!! When trying to %s %x - IP:%x\n", rw ? "write to" : "read from", faultingAddress, regs->eip);
printkf("The page was %s\n", present ? "present" : "not present");
if (reserved)
{
printkf("Reserved bit was set\n");
}
if (id)
{
printkf("Caused by an instruction fetch\n");
}
printkf("CPU was in %s\n", us ? "user-mode" : "supervisor mode");
}
static void handlePageFault(Registers *regs)
{
// A page fault has occurred.
// The faulting address is stored in the CR2 register.
uint32 faultingAddress;
asm volatile("mov %%cr2, %0" : "=r" (faultingAddress));
//Debug_PrintF("page_fault()\n");
//Debug_PrintF("stack of handler is %x\n", &faultingAddress);
Thread* faultingThread = getCurrentThread();
if (NULL != faultingThread)
{
Thread* mainThread = getMainKernelThread();
if (mainThread == faultingThread)
{
printPageFaultInfo(faultingAddress, regs);
PANIC("Page fault in Kernel main thread!!!");
}
else
{
printPageFaultInfo(faultingAddress, regs);
Debug_PrintF("Faulting thread is %d\n", faultingThread->threadId);
if (faultingThread->userMode)
{
Debug_PrintF("Destroying process %d\n", faultingThread->owner->pid);
destroyProcess(faultingThread->owner);
}
else
{
Debug_PrintF("Destroying kernel thread %d\n", faultingThread->threadId);
destroyThread(faultingThread);
}
waitForSchedule();
}
}
else
{
printPageFaultInfo(faultingAddress, regs);
PANIC("Page fault!!!");
}
}
void initializeProcessMmap(Process* process)
{
int page = 0;
for (page = 0; page < RAM_AS_4M_PAGES / 8; ++page)
{
process->mmappedVirtualMemory[page] = 0xFF;
}
//Virtual pages reserved for mmap
for (page = PAGE_INDEX_4M(USER_OFFSET_MMAP); page < (int)(PAGE_INDEX_4M(USER_OFFSET_MMAP_END)); ++page)
{
//? printkf("reserving for mmap: %x\n", page*PAGESIZE_4M);
SET_PAGEFRAME_UNUSED(process->mmappedVirtualMemory, page * PAGESIZE_4M);
}
}
//this functions uses either pAddress or pAddressList
//both of them must not be null!
void* mapMemory(Process* process, uint32 nBytes, uint32 pAddress, List* pAddressList)
{
if (nBytes == 0)
{
return NULL;
}
int pageIndex = 0;
int neededPages = (nBytes / PAGESIZE_4M) + 1;
if (pAddressList)
{
if (List_GetCount(pAddressList) < neededPages)
{
return NULL;
}
}
else if (0 == pAddress)
{
return NULL;
}
int foundAdjacent = 0;
uint32 vMem = 0;
for (pageIndex = PAGE_INDEX_4M(USER_OFFSET_MMAP); pageIndex < (int)(PAGE_INDEX_4M(USER_OFFSET_MMAP_END)); ++pageIndex)
{
if (IS_PAGEFRAME_USED(process->mmappedVirtualMemory, pageIndex))
{
foundAdjacent = 0;
vMem = 0;
}
else
{
if (0 == foundAdjacent)
{
vMem = pageIndex * PAGESIZE_4M;
}
++foundAdjacent;
}
if (foundAdjacent == neededPages)
{
break;
}
}
//Debug_PrintF("mapMemory: needed:%d foundAdjacent:%d vMem:%x\n", neededPages, foundAdjacent, vMem);
if (foundAdjacent == neededPages)
{
uint32 p = 0;
ListNode* pListNode = NULL;
if (pAddressList)
{
pListNode = List_GetFirstNode(pAddressList);
p = (uint32)(uint32*)pListNode->data;
}
else
{
p = pAddress;
}
p = p & 0xFFC00000;
uint32 v = vMem;
for (int i = 0; i < neededPages; ++i)
{
addPageToPd(process->pd, (char*)v, (char*)p, PG_USER);
SET_PAGEFRAME_USED(process->mmappedVirtualMemory, PAGE_INDEX_4M(v));
v += PAGESIZE_4M;
if (pAddressList)
{
pListNode = pListNode->next;
p = (uint32)(uint32*)pListNode->data;
p = p & 0xFFC00000;
}
else
{
p += PAGESIZE_4M;
}
}
return (void*)vMem;
}
return NULL;
}
BOOL unmapMemory(Process* process, uint32 nBytes, uint32 vAddress)
{
if (nBytes == 0)
{
return FALSE;
}
if (vAddress < USER_OFFSET_MMAP)
{
return FALSE;
}
int pageIndex = 0;
int neededPages = (nBytes / PAGESIZE_4M) + 1;
int startIndex = PAGE_INDEX_4M(vAddress);
int endIndex = startIndex + neededPages;
BOOL result = FALSE;
for (pageIndex = startIndex; pageIndex < endIndex; ++pageIndex)
{
if (IS_PAGEFRAME_USED(process->mmappedVirtualMemory, pageIndex))
{
char* vAddr = (char*)(pageIndex * PAGESIZE_4M);
removePageFromPd(process->pd, vAddr, FALSE);
SET_PAGEFRAME_UNUSED(process->mmappedVirtualMemory, vAddr);
result = TRUE;
}
}
return result;
}

48
kernel.soso/vmm.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef VMM_H
#define VMM_H
#include "common.h"
typedef struct Process Process;
typedef struct List List;
extern uint32 *gKernelPageDirectory;
extern uint8 gKernelPageHeapBitmap[];
#define SET_PAGEFRAME_USED(bitmap, pageIndex) bitmap[((uint32) pageIndex)/8] |= (1 << (((uint32) pageIndex)%8))
#define SET_PAGEFRAME_UNUSED(bitmap, p_addr) bitmap[((uint32) p_addr/PAGESIZE_4M)/8] &= ~(1 << (((uint32) p_addr/PAGESIZE_4M)%8))
#define IS_PAGEFRAME_USED(bitmap, pageIndex) (bitmap[((uint32) pageIndex)/8] & (1 << (((uint32) pageIndex)%8)))
#define SET_PAGEHEAP_USED(pageIndex) gKernelPageHeapBitmap[((uint32) pageIndex)/8] |= (1 << (((uint32) pageIndex)%8))
#define SET_PAGEHEAP_UNUSED(p_addr) gKernelPageHeapBitmap[((uint32) p_addr/PAGESIZE_4K)/8] &= ~(1 << (((uint32) p_addr/PAGESIZE_4K)%8))
#define IS_PAGEHEAP_USED(pageIndex) (gKernelPageHeapBitmap[((uint32) pageIndex)/8] & (1 << (((uint32) pageIndex)%8)))
char* getPageFrame4M();
void releasePageFrame4M(uint32 p_addr);
uint32 *getPdFromReservedArea4K();
void releasePdFromReservedArea4K(uint32 *);
void initializeMemory(uint32 high_mem);
uint32 *createPd();
void destroyPd(uint32 *);
uint32 *copyPd(uint32* pd);
BOOL addPageToPd(uint32* pd, char *v_addr, char *p_addr, int flags);
BOOL removePageFromPd(uint32* pd, char *v_addr, BOOL releasePageFrame);
void enablePaging();
void disablePaging();
uint32 getTotalPageCount();
uint32 getUsedPageCount();
uint32 getFreePageCount();
void initializeProcessMmap(Process* process);
void* mapMemory(Process* process, uint32 nBytes, uint32 pAddress, List* pAddressList);
BOOL unmapMemory(Process* process, uint32 nBytes, uint32 vAddress);
#endif // VMM_H

Some files were not shown because too many files have changed in this diff Show More