Browse Source

Add scheduler first release + fix process stack crash

master
Yann MAGNIN 2 years ago
parent
commit
105eb7c482
  1. 14
      Makefile
  2. 18
      include/kernel/devices/timer.h
  3. 80
      include/kernel/hardware/cpg.h
  4. 30
      include/kernel/hardware/tmu.h
  5. 2
      include/kernel/memory.h
  6. 3
      include/kernel/process.h
  7. 6
      include/kernel/scheduler.h
  8. 2
      include/kernel/syscall.h
  9. 3
      include/kernel/unistd_32.h
  10. 20
      include/kernel/util.h
  11. 3
      include/lib/display.h
  12. 1
      include/lib/unistd.h
  13. 12
      include/user/builtin.h
  14. 14
      src/kernel/bootstrap/start.c
  15. 3
      src/kernel/devices/tty/file_op/read.c
  16. 2
      src/kernel/fs/gladfs/filesystem/mount.c
  17. 7
      src/kernel/fs/vfs/dentry/resolve.c
  18. 4
      src/kernel/fs/vfs/inode/mknod.c
  19. 4
      src/kernel/fs/vfs/superblock/mount.c
  20. 16
      src/kernel/hardware/tmu/constructor.c
  21. 19
      src/kernel/hardware/tmu/handler.c
  22. 1
      src/kernel/hardware/vbr/interrupt.c
  23. 52
      src/kernel/hardware/vbr/interrupt_pre.s
  24. 6
      src/kernel/scheduler/context_switch.s
  25. 37
      src/kernel/scheduler/debug.c
  26. 204
      src/kernel/scheduler/handler.S
  27. 4
      src/kernel/scheduler/process/alloc.c
  28. 16
      src/kernel/scheduler/process/get.c
  29. 2
      src/kernel/scheduler/process/initialize.c
  30. 46
      src/kernel/scheduler/schedule.c
  31. 108
      src/kernel/scheduler/start.c
  32. 11
      src/kernel/scheduler/syscall/sys_exit.c
  33. 77
      src/kernel/scheduler/syscall/sys_fexecve.c
  34. 43
      src/kernel/scheduler/syscall/sys_fork.c
  35. 35
      src/kernel/syscall/handler.c
  36. 1
      src/kernel/syscall/syscall_pre.s
  37. 59
      src/kernel/util/kvram.c
  38. 72
      src/kernel/util/timer.c
  39. 12
      src/lib/display/dclr_str_area.S
  40. 12
      src/lib/unistd/fexecve.S
  41. 18
      src/user/shell/Makefile
  42. 43
      src/user/shell/builtin/proc.c
  43. 5
      src/user/shell/shell.ld
  44. 96
      src/user/shell/util/check_builtin.c
  45. 106
      src/user/test/Makefile
  46. 21
      src/user/test/test.c
  47. 65
      src/user/test/test.ld
  48. 4
      src/user/test/test_asm.s

14
Makefile

@ -7,6 +7,7 @@
KERNEL := output/vhex.g1a
USER := output/shell.elf
TEST := output/test.elf
##---
@ -15,11 +16,13 @@ USER := output/shell.elf
all:
@ make --no-print-directory -C src/lib
@ make --no-print-directory -C src/kernel
@ make --no-print-directory -C src/user
@ make --no-print-directory -C src/user/shell
@ make --no-print-directory -C src/user/test
install: all
sudo p7 send --force --no-term $(KERNEL)
sudo p7 send --force --directory=VHEX $(USER)
sudo p7 send --force --no-term --directory=VHEX $(USER)
sudo p7 send --force --directory=VHEX $(TEST)
@ -30,12 +33,15 @@ install: all
clean:
make clean --no-print-directory -C src/lib
make clean --no-print-directory -C src/kernel
make clean --no-print-directory -C src/user
make clean --no-print-directory -C src/user/shell
make clean --no-print-directory -C src/user/test
fclean: clean
make fclean --no-print-directory -C src/lib
make fclean --no-print-directory -C src/kernel
make fclean --no-print-directory -C src/user
make fclean --no-print-directory -C src/user/shell
make fclean --no-print-directory -C src/user/test
rm -rf build
re: fclean all

18
include/kernel/devices/timer.h

@ -1,18 +0,0 @@
#ifndef __KERNEL_DEVICES_TIMER_H__
# define __KERNEL_DEVICES_TIMER_H__
#include <stddef.h>
#include <stdint.h>
// TODO: MOVE ME !!!!!!!!
#define TIMER_NUMBER 3
#define TIMER_UNUSED 0xff
struct timer_cache_s
{
void *callback;
volatile void *arg;
uint8_t status;
};
#endif /*__KERNEL_DEVICES_TIMER_H__*/

80
include/kernel/hardware/cpg.h

@ -0,0 +1,80 @@
#ifndef __KERNEL_HARDWARE_CPG_H__
# define __KERNEL_HARDWARE_CPG_H__
#include <stddef.h>
#include <stdint.h>
#include <kernel/def/union_types.h>
#include <kernel/def/attributes.h>
struct SH7305_cpg_s
{
volatile long_union(FRQCRA, /* Casio's configuration: 0x0f212213 */
uint32_t KICK : 1; /* Kick bits */
uint32_t const : 1; /* All 0 */
uint32_t STC : 6; /* PLL circuit multiplication ratio */
uint32_t IFC : 4; /* CPU clock frequency division ratio */
uint32_t const : 4; /* All 0 */
uint32_t SFC : 4; /* S clock frequency division ratio */
uint32_t BFC : 4; /* Bus clock frequency division ration */
uint32_t const : 4; /* All 0 */
uint32_t PFC : 4; /* Peripheral clock frequency division ratio */
);
volatile uint32_t FRQCRB; /* Undocumented (0x00000000) */
volatile long_union(FCLKACR, /* Casio's configuration: 0x00000157 */
uint32_t const : 16; /* All 0 */
uint32_t unknown : 16; /* Unknown (default 0x0157) */
);
volatile long_union(FCLKBCR, /* Casio's configuration: 0x0000003f */
uint32_t const : 16; /* All 0 */
uint32_t unknown : 16; /* Unknown (default 0x003f) */
);
GAPS(0x08);
volatile long_union(IRDACLKCR, /* Casio's configuration: 0x0000003f */
uint32_t const : 16; /* All 0 */
uint32_t unknown : 16; /* Unknown (default 0x003f) */
);
GAPS(0x08);
volatile long_union(PLLCR, /* Casio's configuration: 0x00005000 */
uint32_t const : 16; /* All 0 */
uint32_t unknown0 : 1; /* Unknown (default 0) */
uint32_t PLLE : 1; /* PLL enable (?) */
uint32_t const : 1; /* All 0 */
uint32_t FLLE : 1; /* FLL enable (?) */
uint32_t const : 8; /* All 0 */
uint32_t unknown1 : 4; /* Unknown (default 0b0000) */
);
GAPS(0x14);
volatile long_union(SPUCLKCR, /* Casio's configuration: 0x00000103 */
uint32_t const : 16; /* All 0 */
uint32_t unknown : 16; /* Unknown (default 0x0103) */
);
GAPS(0x08);
volatile long_union(VCLKCR, /* Casio's configuration: 0x0000003f */
uint32_t const : 16; /* All 0 */
uint32_t unknown : 16; /* Unknown (default 0x003f) */
);
GAPS(0x04);
volatile long_union(FLLFRQ, /* Casio's configuration: 0x00004384 */
uint32_t const : 16; /* All 0 */
uint32_t SELXM : 2; /* FLL output division */
uint32_t unknown : 3; /* Unknown */
uint32_t FLF : 11; /* FLL Multiplication Ratio */
);
GAPS(0x0c);
volatile long_union(LSTATS,
uint32_t const : 31; /* All 0 */
uint32_t const FQRF : 1; /* Frequency change status */
);
};
#define SH7305_CPG (*(volatile struct SH7305_cpg_s *)0xa4150000)
#endif /*__KERNEL_HARDWARE_CPG_H__*/

30
include/kernel/hardware/tmu.h

@ -8,29 +8,29 @@
struct timer_s
{
volatile uint32_t TCOR; /* Timer Constant register */
volatile uint32_t TCNT; /* Timer Counter */
volatile word_union(TCR, /* Timer Control Register */
uint16_t const : 7; /* All 0 */
uint16_t UNF : 1; /* Underflow flags */
uint16_t const : 2; /* All 0 */
uint16_t UNIE : 1; /* Underflow interrup control */
uint16_t const : 2; /* All 0 */
uint16_t TPSC : 3; /* Time prescaler */
volatile uint32_t TCOR; /* Timer Constant register */
volatile uint32_t TCNT; /* Timer Counter */
volatile word_union(TCR, /* Timer Control Register */
uint16_t const : 7; /* All 0 */
uint16_t UNF : 1; /* Underflow flags */
uint16_t const : 2; /* All 0 */
uint16_t UNIE : 1; /* Underflow interrup control */
uint16_t CKREG : 2; /* Input Clock edge */
uint16_t TPSC : 3; /* Time prescaler */
);
GAPS(2);
};
struct __sh7305_tmu_s
{
volatile byte_union(TSTR, /* Timer Start Register */
uint8_t const : 5; /* All 0 */
uint8_t STR2 : 1; /* Counter start 2 */
uint8_t STR1 : 1; /* Counter start 1 */
uint8_t STR0 : 1; /* Counter start 0 */
volatile byte_union(TSTR, /* Timer Start Register */
uint8_t const : 5; /* All 0 */
uint8_t STR2 : 1; /* Counter start 2 */
uint8_t STR1 : 1; /* Counter start 1 */
uint8_t STR0 : 1; /* Counter start 0 */
);
GAPS(3);
volatile struct timer_s TIMER[3];
volatile struct timer_s TIMER[3]; /* Timers */
};
#define SH7305_TMU (*(volatile struct __sh7305_tmu_s *)0xa4490004)

2
include/kernel/memory.h

@ -15,7 +15,7 @@ struct pm_block_cache_s
} status;
// Space informations.
uint16_t start;
uint32_t start;
uint32_t end;
// Linked list

3
include/kernel/process.h

@ -14,8 +14,6 @@
#define PROCESS_NAME_LENGHT (16)
#define PROCESS_MAX (4)
#define PROC_IDLE (0)
// define process struct.
//TODO: signal !
struct process
@ -93,6 +91,7 @@ struct process_stack
// Functions.
extern struct process *process_create(const char *name);
extern struct process *process_get(pid_t pid);
extern pid_t process_get_pid(struct process *process);
extern int process_switch(pid_t pid);
// Internal function.

6
include/kernel/scheduler.h

@ -59,10 +59,10 @@ extern int sched_add_task(struct process *process);
extern void sched_start(void);
/*
** Save current context of the current task and run the
** next one based on internal task priority.
** Get the current task context and the next one
** based on internal task priority / status.
*/
extern void sched_schedule(void);
extern int sched_schedule(common_context_t **current, common_context_t **next);
/*
** Internal function wich will switch current process

2
include/kernel/syscall.h

@ -14,6 +14,8 @@ extern pid_t sys_fork(void);
extern pid_t sys_getpid(void);
extern pid_t sys_getppid(void);
extern pid_t sys_waitpid(pid_t pid, int *wstatus, int options);
extern pid_t sys_fexecve(const char *pathname);
extern void sys_exit(int status);
extern int sys_open(const char *pathname, int flags, ...);
extern ssize_t sys_write(int fd, const void *buf, size_t count);

3
include/kernel/unistd_32.h

@ -6,7 +6,7 @@
// Process
#define __NR_exit 1
#define __NR_exec 2
#define __NR_fexecve 2
#define __NR_waitpid 3
// VFS
@ -27,6 +27,7 @@
#define __NR_kvram_ascii 12
#define __NR_kvram_reverse 13
#define __NR_kvram_scroll 14
#define __NR_kvram_clr_str_area 15
//TODO: keyboard

20
include/kernel/util.h

@ -18,9 +18,9 @@ extern size_t strlen(char const *str);
extern void kvram_clear(void);
extern void kvram_display(void);
extern void kvram_scroll(int lines);
extern void kvram_reverse(int x, int y, int width, int height);
extern void kvram_print(int x, int y, char const *str);
extern void kvram_ascii(int x, int y, char const c);
extern void kvram_reverse(int x, int y, int width, int height);
extern void kvram_clr_str_area(int x, int y, int width, int height);
// Kernel printf-wrapper
extern void printk(int x, int y, char const *str, ...);
@ -28,9 +28,21 @@ extern void printk(int x, int y, char const *str, ...);
// Hardware specific function (do not use !)
extern void t6k11_display(void *vram);
// Timer functions.
//---
// Timer functions.
//---
#define TIMER_NUMBER 3
#define TIMER_UNUSED 0xff
struct timer_cache_s
{
void *callback;
volatile void *arg;
uint8_t status;
};
extern int timer_uninstall(int timer_ID);
extern int timer_install(void *callback, void *arg, uint32_t delay_ms, uint8_t mode);
extern int timer_install(void *callback, void *arg, uint32_t ticks, uint8_t mode);
extern int timer_start(int timer_ID);
// Debug wait
#define DBG_WAIT for(int i = 0 ; i < 3000000 ; i++)

3
include/lib/display.h

@ -6,7 +6,8 @@
// Draw primtives
extern void dclear(void);
extern void dprint(int x, int y, char const *str);
extern void dclr_str_area(int x, int y, int with, int height);
extern void dprint(int x, int y, char const *str, ...);
extern void dascii(int x, int y, char const c);
extern void dreverse(int x, int y, int width, int height);
extern void dscroll(int line);

1
include/lib/unistd.h

@ -14,6 +14,7 @@
#define WUNTRACED 1
#define WCONTINUED 2
extern pid_t waitpid(pid_t pid, int *wstatus, int options);
extern pid_t fexecve(const char *pathname);
// File syscall
#define O_DIRECT 0

12
include/user/builtin.h

@ -4,14 +4,6 @@
#include <stddef.h>
#include <stdint.h>
#define VHEX_BUILTIN(bname) \
static int bname(int argc, char **argv); \
__attribute__((section(".builtin"))) \
struct builtin_s _##bname = { \
.name = #bname, \
.entry = &bname \
}; \
static int bname(int argc, char **argv)
// Define builtin struct.
struct builtin_s
@ -20,5 +12,9 @@ struct builtin_s
int (*entry)(int argc, char **argv);
};
// Builtin list
extern int builtin_proc(void);
extern int builtin_ram(void);
#endif /*__USER_BUILTIN_H__*/

14
src/kernel/bootstrap/start.c

@ -174,9 +174,9 @@ int start(void)
if (vhex_process == NULL)
{
kvram_clear();
kvram_print(0, 0, "Vhex fatal error !");
kvram_print(0, 1, "First process error !");
kvram_print(0, 2, "Wait manual reset...");
printk(0, 0, "Vhex fatal error !");
printk(0, 1, "First process error !");
printk(0, 2, "Wait manual reset...");
kvram_display();
while (1) { __asm__ volatile ("sleep"); }
}
@ -188,9 +188,9 @@ int start(void)
{
// Display message.
kvram_clear();
kvram_print(0, 0, "Vhex fatal error !");
kvram_print(0, 1, "File \"VHEX/shell.elf\" not found !");
kvram_print(0, 2, "Press [MENU key]...");
printk(0, 0, "Vhex fatal error !");
printk(0, 1, "File \"VHEX/shell.elf\" not found !");
printk(0, 2, "Press [MENU key]...");
kvram_display();
// Restore Casio context.
@ -225,7 +225,7 @@ int start(void)
// normally the kernel SHOULD / CAN not arrive here.
kvram_clear();
kvram_print(0, 0, "Kernel job fini !");
printk(0, 0, "Kernel job fini !");
kvram_display();
while (1)
{

3
src/kernel/devices/tty/file_op/read.c

@ -42,7 +42,8 @@ ssize_t tty_read(void *inode, void *buffer, size_t count)
keyboard.saved.tty.cursor.y = tty.cursor.y;
// Initialize timer for cursor.
timer_fd = timer_install(&cursor_callback, &keyboard, 500, 1);
// FIXME: find real ticks value !!
timer_fd = timer_install(&cursor_callback, &keyboard, 500 * 500 * 2, 1);
if (timer_fd == -1)
return (0);

2
src/kernel/fs/gladfs/filesystem/mount.c

@ -19,7 +19,7 @@ void *gladfs_mount(void)
if (gladfs_superblock.root_inode == NULL)
{
kvram_clear();
kvram_print(0, 0, "GladFS: ROOT inode alloc error !");
printk(0, 0, "GladFS: ROOT inode alloc error !");
kvram_display();
DBG_WAIT;
}

7
src/kernel/fs/vfs/dentry/resolve.c

@ -24,7 +24,7 @@ static int get_name(int *name_lenght, const char *path, char *name)
return (0);
}
//TODO add '..' handling.
//TODO: update ?
struct dentry *vfs_dentry_resolve(const char *path, int mode)
{
extern struct process *process_current;
@ -114,7 +114,6 @@ struct dentry *vfs_dentry_resolve(const char *path, int mode)
printk(0, 3, "name: %s$", name);
kvram_display();
DBG_WAIT;
while (1);
return (NULL);
}
}
@ -138,7 +137,7 @@ struct dentry *vfs_dentry_resolve(const char *path, int mode)
// Try to find first child
next = vfs_dentry_find_first_child(next);
if (next != NULL)
/*if (next != NULL)
{
// Debug !
kvram_clear();
@ -148,7 +147,7 @@ struct dentry *vfs_dentry_resolve(const char *path, int mode)
printk(0, 3, "name: %s$", name);
kvram_display();
DBG_WAIT;
}
}*/
// Update name lenght to skip '/' char
name_lenght = name_lenght + 1;

4
src/kernel/fs/vfs/inode/mknod.c

@ -62,7 +62,7 @@ int vfs_mknod(const char *pathname, mode_t mode, dev_t dev)
// Debug !
kvram_clear();
/*kvram_clear();
printk(0, 0, "New mknod device !");
printk(0, 1, "dentry: %p$", file);
printk(0, 2, "inode: %p$", file->inode);
@ -70,7 +70,7 @@ int vfs_mknod(const char *pathname, mode_t mode, dev_t dev)
printk(0, 4, "dev->file_op: %p$", &device->file_op);
kvram_display();
DBG_WAIT;
DBG_WAIT;
DBG_WAIT;*/
// Set file operations
file->dentry_op.file_op = &device->file_op;

4
src/kernel/fs/vfs/superblock/mount.c

@ -67,13 +67,13 @@ int vfs_mount(const char *source, const char *target,
vfs_root_node->dentry_op.inode_op = &filesystem->inode_operations;
// Debug !
kvram_clear();
/*kvram_clear();
printk(0, 0, "vfs_root_node = %p", vfs_root_node);
printk(0, 1, "vfs_root_node = %s$", vfs_root_node->name);
printk(0, 2, "vfs_root_node = %p", vfs_root_node->child);
printk(0, 3, "vfs_root_node = %p", vfs_root_node->next);
kvram_display();
DBG_WAIT;
DBG_WAIT;*/
return (0);
}

16
src/kernel/hardware/tmu/constructor.c

@ -1,16 +0,0 @@
#include <kernel/hardware/tmu.h>
#include <kernel/devices/timer.h>
// Internal timer "cache".
struct timer_cache_s timercache[TIMER_NUMBER];
__attribute__((constructor))
void timer_constructor(void)
{
for (int i = 0 ; i < TIMER_NUMBER ; i = i + 1)
{
timercache[i].status = TIMER_UNUSED;
timercache[i].callback = NULL;
timercache[i].arg = NULL;
}
}

19
src/kernel/hardware/tmu/handler.c

@ -1,9 +1,10 @@
#include <kernel/hardware/tmu.h>
#include <kernel/devices/timer.h>
#include <kernel/util.h>
void timer_handler(void)
{
extern struct timer_cache_s timercache[TIMER_NUMBER];
static uint32_t counter = 0;
uint32_t intevt;
int timer_ID;
@ -11,10 +12,18 @@ void timer_handler(void)
// @note: tricky way to get timer ID
// TODO: find better way !
intevt = *(uint32_t*)0xff000028;
timer_ID = (intevt - 0x400) >> 9;
timer_ID = (intevt - 0x400) / 0x20;
// Stop timer flag and clear interrupt flags.
SH7305_TMU.TSTR.BYTE &= ~(1 << timer_ID);
/*if (intevt != 0x400)
{
kvram_clear();
printk(0, 0, "Timer ID: %d\n", timer_ID);
printk(0, 1, "Interrupt: %#x\n", intevt);
printk(0, 2, "counter: %d\n", counter++);
kvram_display();
}*/
// Clear interrupt flags.
SH7305_TMU.TIMER[timer_ID].TCR.UNF = 0;
// Execute callback if possible.
@ -24,6 +33,4 @@ void timer_handler(void)
((void (*)(volatile void *))timercache[timer_ID].callback)(timercache[timer_ID].arg);
}
// Re-start timer.
SH7305_TMU.TSTR.BYTE |= 1 << timer_ID;
}

1
src/kernel/hardware/vbr/interrupt.c

@ -4,7 +4,6 @@
extern void keysc_handler(void);
extern void timer_handler(void);
__attribute__((section(".vhex.interrupt"), interrupt_handler))
void interrupt_handler(void)
{
uint32_t intevt = *(uint32_t*)0xff000028;

52
src/kernel/hardware/vbr/interrupt_pre.s

@ -0,0 +1,52 @@
.section ".vhex.interrupt", "awx", @progbits
.global _interrupt_handler_pre
.type _interrupt_handler_pre, @function
.extern _sched_timer_intevt
.extern _sched_handler
.extern _interrupt_handler
_interrupt_handler_pre:
! Due to PR register used to switch process
! context, we SHOULD catch scheduler timer
! interrupt before the interrupt handler because
! we need to save / restore pr register before
! context swtich.
mov.l .sched_timer_intevt, r0 ! get the precalculate scheduler timer event
mov.l .intevt_register, r1 ! get INTEVT register address
mov.l @r0, r0 ! get the scheduler event code
mov.l @r1, r1 ! get the interrupt event
cmp/eq r0, r1 ! if scheduler timer event == INTEVT...
bf general_interrupt ! ...if not, jump at <general_interrupt>
scheduler_interrupt:
mov.l .scheduler_handler, r0 ! get scheduler handler address
jmp @r0 ! jump into scheduler handler
nop ! (db) nop
general_interrupt:
! Save critical regsiter.
stc.l spc, @-r15 ! save SPC register.
stc.l ssr, @-r15 ! save SSR register.
sts.l pr, @-r15 ! save pr register.
! Call interrupt handler
mov.l .interrupt_handler, r0 ! get interrupt handler address
jsr @r0 ! call interurpt handler
nop ! (db) nop
! Restore critical regsiter
lds.l @r15+, pr ! restore PR register.
ldc.l @r15+, ssr ! restore SSR regsiter.
ldc.l @r15+, spc ! restore SPC regsiter.
! Return
rte ! exit
nop ! (db) nop
.align 4
.sched_timer_intevt: .long _sched_timer_intevt
.scheduler_handler: .long _sched_handler
.interrupt_handler: .long _interrupt_handler
.intevt_register: .long 0xff000028

6
src/kernel/scheduler/context_switch.s

@ -44,10 +44,10 @@ save_current_context:
! @note: current process can be NULL !
tst r4, r4 ! if current task == NULL...
bt context_load ! ...if yes, jump at <context_switch>
add #88, r4 ! get &process->context (end)
add #84, r4 ! get &process->context (end)
! save current context
sts.l pr, @-r4 ! get pr regsiter
!sts.l pr, @-r4 ! get pr regsiter
stc.l spc, @-r4 ! get spc regsiter
stc.l ssr, @-r4 ! get ssr regsiter
sts.l mach, @-r4 ! get mach regsiter
@ -95,7 +95,7 @@ context_load:
lds.l @r5+, mach ! set mach regsiter
ldc.l @r5+, ssr ! set ssr regsiter
ldc.l @r5+, spc ! set spc regsiter
lds.l @r5+, pr ! set pr regsiter
!lds.l @r5+, pr ! set pr regsiter
! Process switch

37
src/kernel/scheduler/debug.c

@ -0,0 +1,37 @@
#include <kernel/context.h>
#include <kernel/hardware/tmu.h>
#include <kernel/util.h>
// Test
uint32_t counter = 0;
void sched_debug(common_context_t *context_current, common_context_t *context_next)
{
extern uint32_t sched_timer_id;
extern uint32_t sched_timer_address;
uint32_t tstr = SH7305_TMU.TSTR.BYTE;
uint32_t tcr = *(uint16_t*)sched_timer_address;
uint32_t tcor = *(uint32_t*)(sched_timer_address - 4);
uint32_t tcnt = *(uint32_t*)(sched_timer_address - 8);
//SH7305_TMU.TSTR.STR2 = 0;
//SH7305_TMU.TSTR.STR1 = 0;
//SH7305_TMU.TSTR.STR0 = 0;
//SH7305_TMU.TIMER[0].TCR.UNF = 0;
//SH7305_TMU.TIMER[1].TCR.UNF = 0;
//SH7305_TMU.TIMER[2].TCR.UNF = 0;
kvram_clear();
printk(0, 0, "Scheduler_schudele !");
printk(0, 1, "context current = %p", context_current);
printk(0, 2, "context next = %p", context_next);
printk(0, 3, "counter = %#x", counter++);
printk(0, 4, "TSTR: %#x", tstr);
printk(0, 5, "TCOR: %#x", tcor);
printk(0, 6, "TCNT: %#x", tcnt);
printk(0, 7, "TCR: %#x", tcr);
kvram_display();
}

204
src/kernel/scheduler/handler.S

@ -0,0 +1,204 @@
.text
.global _sched_handler
.type _sched_handler, @function
.extern _sched_timer_id
.extern _sched_timer_address
.extern _sched_schedule
.align 2
/*
** @note
** We can use only r0 - r7 register because
** we SHOULD not modify the current process context.
*/
_sched_handler:
/*
** Stop scheduler timer and clear interrupt flags
*/
stop_clear_sched_timer:
! Clear scheduler timer interrupt
mov.l .sched_timer_address, r0 ! get precalculated scheduler timer address
mov.l .timer_unf_field, r1 ! get TIMER.TCR.UNF byte field
mov.l @r0, r0 ! get scheduler timer TCR register
mov.w @r0, r2 ! get scheduler timer TCR register
not r1, r1 ! get interrupt flags bit mask (to remove)
and r1, r2 ! clear timer interrupt flags
mov.w r2, @r0 ! update timer TCR
! Stop scheduler timer
mov.l .sched_timer_tstr_bit, r0 ! get precalculated scheduler timer ID
mov.l .timer_tstr_register, r1 ! get TMU0.TSTR base address
mov.l @r0, r0 ! get scheduler timer ID
mov.b @r1, r2 ! get TMU0.TSTR data
not r0, r0 ! get TSTR scheduler timer ID mask (to remove)
and r0, r2 ! stop scheduler timer
mov.b r2, @r1 ! update TMU0.TSTR
#ifdef __SCHED_DEBUG__
sts.l pr, @-r15 ! save pr register
mov #0, r4 ! save r4 register (current context)
mov #0, r5 ! save r5 register (next context)
mov.l .sched_debug, r0 ! get sched_debug() absraction
jsr @r0 ! call abstraction
nop ! (db) nop
lds.l @r15+, pr ! restore pr register
bra restart_sched_timer
nop
#endif
/*
** Get current and next context
*/
get_contexts:
! prologue
mov.l r9, @-r15 ! save r9 register
mov.l r8, @-r15 ! save r8 register
sts.l pr, @-r15 ! save pr register
! Create to context_common_t **ptr
add #-4, r15 ! create first context pointer
mov r15, r8 ! save first context pointer
add #-4, r15 ! create second context pointer
mov r15, r9 ! save second context pointer
add #-4, r15 ! create context pointer
mov.l r15, @r8 ! save context pointer
add #-4, r15 ! create context pointer
mov.l r15, @r9 ! save context pointer
! call high level abstraction
mov r8, r4 ! send current contexts pointer
mov r9, r5 ! send next context pointer
mov.l .sched_schedule, r0 ! get sched_scheduler() abstraction address
jsr @r0 ! call sched_schedule() abstract
nop ! (db) nop
! Restore stack and register (epilogue)
mov.l @r8, r4 ! save current context
mov.l @r9, r5 ! save next context
add #16, r15 ! restore stack
lds.l @r15+, pr ! restore pr register
mov.l @r15+, r8 ! restore r8 register
mov.l @r15+, r9 ! restore r9 register
! Check context error
tst r0, r0 ! check if returned value == 0...
bt debug ! if yes, jump at <debug>
bra restart_sched_timer ! jump at <restart_sched_timer>
nop ! (db) nop
/*
** Debug part, used to debug the contexts
*/
debug:
#ifdef __SCHED_DEBUG__
sts.l pr, @-r15 ! save pr register
mov.l r4, @-r15 ! save r4 register (current context)
mov.l r5, @-r15 ! save r5 register (next context)
mov.l .sched_debug, r0 ! get sched_debug() absraction
jsr @r0 ! call abstraction
nop ! (db) nop
mov.l @r15+, r5 ! restore r5 register
mov.l @r15+, r4 ! restore r4 register
lds.l @r15+, pr ! restore pr register
#endif
/*
** Context switch
*/
save_current_context:
! Check current process
! @note: current process can be NULL !
tst r4, r4 ! if current task == NULL...
bt next_context_load ! ...if yes, jump at <context_switch>
add #88, r4 ! get &process->context (end)
! save current context
sts.l pr, @-r4 ! get pr regsiter
stc.l spc, @-r4 ! get spc regsiter
stc.l ssr, @-r4 ! get ssr regsiter
sts.l mach, @-r4 ! get mach regsiter
sts.l macl, @-r4 ! get macl regsiter
stc.l gbr, @-r4 ! get gbr regsiter
mov.l r15, @-r4 ! get r15 register
mov.l r14, @-r4 ! get r14 regsiter
mov.l r13, @-r4 ! get r13 regsiter
mov.l r12, @-r4 ! get r12 regsiter
mov.l r11, @-r4 ! get r11 regsiter
mov.l r10, @-r4 ! get r10 regsiter
mov.l r9, @-r4 ! get r9 regsiter
mov.l r8, @-r4 ! get r8 regsiter
stc.l R7_BANK, @-r4 ! get "process" r7 regsiter
stc.l R6_BANK, @-r4 ! get "process" r6 regsiter
stc.l R5_BANK, @-r4 ! get "process" r5 regsiter
stc.l R4_BANK, @-r4 ! get "process" r4 regsiter
stc.l R3_BANK, @-r4 ! get "process" r3 regsiter
stc.l R2_BANK, @-r4 ! get "process" r2 regsiter
stc.l R1_BANK, @-r4 ! get "process" r1 regsiter
stc.l R0_BANK, @-r4 ! get "process" r0 regsiter
next_context_load:
! Load next process
! @note: next process can not be NULL !
ldc.l @r5+, R0_BANK ! set "process" r0 regsiter
ldc.l @r5+, R1_BANK ! set "process" r1 regsiter
ldc.l @r5+, R2_BANK ! set "process" r2 regsiter
ldc.l @r5+, R3_BANK ! set "process" r3 regsiter
ldc.l @r5+, R4_BANK ! set "process" r4 regsiter
ldc.l @r5+, R5_BANK ! set "process" r5 regsiter
ldc.l @r5+, R6_BANK ! set "process" r6 regsiter
ldc.l @r5+, R7_BANK ! set "process" r7 regsiter
mov.l @r5+, r8 ! set r8 regsiter
mov.l @r5+, r9 ! set r9 regsiter
mov.l @r5+, r10 ! set r10 regsiter
mov.l @r5+, r11 ! set r11 regsiter
mov.l @r5+, r12 ! set r12 regsiter
mov.l @r5+, r13 ! set r13 regsiter
mov.l @r5+, r14 ! set r14 regsiter
mov.l @r5+, r15 ! set r15 register
ldc.l @r5+, gbr ! set gbr regsiter
lds.l @r5+, macl ! set macl regsiter
lds.l @r5+, mach ! set mach regsiter
ldc.l @r5+, ssr ! set ssr regsiter
ldc.l @r5+, spc ! set spc regsiter
lds.l @r5+, pr ! set pr regsiter
/*
** Restart timer
*/
restart_sched_timer:
mov.l .sched_timer_tstr_bit, r0 ! get precalculated scheduler timer ID
mov.l .timer_tstr_register, r1 ! get TMU0.TSTR base address
mov.l @r0, r0 ! get scheduler timer ID
mov.b @r1, r2 ! get TMU0.TSTR data
or r0, r2 ! start scheduler timer
mov.b r2, @r1 ! update TMU0.TSTR
/*
** Process switch
*/
process_switch:
rte ! use RTE to switch process
nop ! (db) nop
.align 4
.sched_timer_tstr_bit: .long _sched_timer_tstr_bit
.sched_timer_address: .long _sched_timer_address
.sched_schedule: .long _sched_schedule
.timer_tstr_register: .long 0xa4490004
.timer_unf_field: .long 0x00000100
#ifndef __SCHED_DEBUG__
.sched_debug: .long _sched_debug
#endif
.end

4
src/kernel/scheduler/process/alloc.c

@ -2,14 +2,16 @@
// This function SHOULD NOT be called
// without atomic operation !!
// TODO: dynamic allocation ?
pid_t process_alloc(struct process **process)
{
extern struct process_stack process_stack[PROCESS_MAX];
for (int i = 0 ; i < PROCESS_MAX ; i = i + 1)
{
if (process_stack[i].status == PROC_IDLE)
if (process_stack[i].status == PROC_UNUSED)
{
process_stack[i].status = PROC_USED;
*process = &process_stack[i].process;
return (i);
}

16
src/kernel/scheduler/process/get.c

@ -1,6 +1,6 @@
#include <kernel/process.h>
struct process *process_get(pid_t pid)
struct process *process_get_proc(pid_t pid)
{
extern struct process_stack process_stack[PROCESS_MAX];
@ -11,3 +11,17 @@ struct process *process_get(pid_t pid)
// Return process.
return (&process_stack[pid].process);
}
pid_t process_get_pid(struct process *target)
{
extern struct process_stack process_stack[PROCESS_MAX];
int i;
i = -1;
while (++i < PROCESS_MAX)
{
if (&process_stack[i].process == target)
return (i);
}
return (-1);
}

2
src/kernel/scheduler/process/initialize.c

@ -10,6 +10,6 @@ void process_constructor(void)
// Set all process to idle state.
for (int i = 0 ; i < PROCESS_MAX ; i = i + 1)
{
process_stack[i].status = PROC_IDLE;
process_stack[i].status = PROC_UNUSED;
}
}

46
src/kernel/scheduler/schedule.c

@ -3,26 +3,20 @@
#include <kernel/util.h>
//TODO: assembly !
void sched_schedule(void)
// @note: This part *SHOULD* be exeption safe !
int sched_schedule(common_context_t **context_current, common_context_t **context_next)
{
extern struct sched_task *sched_task_current;
extern struct sched_task *sched_task_queue;
struct sched_task *task_current;
struct sched_task *task_next;
common_context_t *context_current;
common_context_t *context_next;
// Start atomic operation
atomic_start();
// Check current task
// TODO: check process status !!
if (sched_task_current == NULL)
{
task_current = NULL;
task_next = (sched_task_queue != NULL)
? sched_task_queue
: NULL;
task_next = (sched_task_queue != NULL) ? sched_task_queue : NULL;
} else {
task_current = sched_task_current;
task_next = (sched_task_current->next != NULL)
@ -32,39 +26,23 @@ void sched_schedule(void)
// Check potantial error
if (task_next == NULL || task_next == sched_task_current)
{
atomic_stop();
return;
}
//TODO: check process status !!!
return (-1);
// Update internal scheduler task cursor
sched_task_current = task_next;
// Get context
context_current =
(task_current != NULL)
? &task_current->process->context
: NULL;
context_next =
(task_next != NULL)
? &task_next->process->context
: NULL;
*context_current = (task_current != NULL) ? &task_current->process->context : NULL;
*context_next = &task_next->process->context;
// DEBUG !
kvram_clear();
/*kvram_clear();
printk(0, 0, "Scheduler_schudele !");
printk(0, 1, "task current = %p", task_current);
printk(0, 2, "task next = %p", task_next);
printk(0, 3, "context current = %p", context_current);
printk(0, 4, "context next = %p", context_next);
printk(0, 3, "context current = %p", *context_current);
printk(0, 4, "context next = %p", *context_next);
kvram_display();
DBG_WAIT;
printk(0, 5, "context switch !");
kvram_display();
// Context switch
sched_context_switch(context_current, context_next);
DBG_WAIT;*/
return (0);
}

108
src/kernel/scheduler/start.c

@ -1,12 +1,114 @@
#include <kernel/scheduler.h>
#include <kernel/hardware/cpg.h>
#include <kernel/hardware/tmu.h>
#include <kernel/util.h>
// Internal data used by the scheduler handler
uint32_t sched_timer_id = 0;
uint32_t sched_timer_address = 0;
uint32_t sched_timer_intevt = 0;
uint32_t sched_timer_tstr_bit = 0;
// Internal private function
//void sched_handler(void);
//FIXME: remove me and wrap timer interrupt when occur !!
static void scheduler_timer_callback(void)
{
common_context_t *context_current;
common_context_t *context_next;
//TODO: quantum handling !!
//TODO: scheduler block / unblock options !!
//FIXME: Get SPC, SSR, ... !!
// Get current context and
if (sched_schedule(&context_current, &context_next) != 0)
return;
// Debug
//kvram_clear();
//printk(0, 0, "Scheduler_schudele !");
//printk(0, 1, "context current = %p", context_current);
//printk(0, 2, "context next = %p", context_next);
//kvram_display();
//printk(0, 3, "context switch !");
//kvram_display();
//DBG_WAIT;
// Context switch
sched_context_switch(context_current, context_next);
}
void sched_start(void)
{
extern struct sched_task *sched_task_queue;
extern struct process *process_current;
uint32_t fll_freq;
uint32_t pll_freq;
uint32_t cpu_freq;
uint32_t bus_freq;
uint32_t per_freq;
//TODO: get CPU frequency !
//TODO: setup TMU0 interrupt !
// Calculate FLL frequency (Khz)
// @note: RCLK = 32 768 Hz
fll_freq = SH7305_CPG.FLLFRQ.FLF * 32768; // Hz
fll_freq = fll_freq / (1 << SH7305_CPG.FLLFRQ.SELXM); // Check FLL output division
// Calculate PLL frequency (Khz)
pll_freq = fll_freq * (SH7305_CPG.FRQCRA.STC + 1);
// Calculate CPU clock frequency !
cpu_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.IFC + 1));
// Calculate BUS clock frequency !
bus_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.BFC + 1));
// Calculate Peripheral clock frequency !
per_freq = pll_freq / (1 << (SH7305_CPG.FRQCRA.PFC + 1));
// Debug
kvram_clear();
printk(0, 0,
"FLL freq: %d.%d Mhz\n"
"PLL freq: %d.%d Mhz\n"
"CPU freq: %d.%d Mhz\n"
"BUS freq: %d.%d Mhz\n"
"Per freq: %d.%d Mhz",
fll_freq / 1000000, (((fll_freq - ((fll_freq / 1000000)) * 1000000)) + 999) / 1000,
pll_freq / 1000000, (((pll_freq - ((pll_freq / 1000000)) * 1000000)) + 999) / 1000,
cpu_freq / 1000000, (((cpu_freq - ((cpu_freq / 1000000)) * 1000000)) + 999) / 1000,
bus_freq / 1000000, (((bus_freq - ((bus_freq / 1000000)) * 1000000)) + 999) / 1000,
per_freq / 1000000, (((per_freq - ((per_freq / 1000000)) * 1000000)) + 999) / 1000
);
kvram_display();
DBG_WAIT;
// Register first process !
process_current = sched_task_queue->process;
sched_schedule();
// Setup TMU0 (scheduler) interrupt !
// @note: I use Po/4 on TMU prescaler
// TODO: generate quantum and quantum counter for preemption !
uint32_t ticks = (per_freq / 4) / 16;
//sched_timer_id = timer_install(scheduler_timer_callback, NULL, ticks, 0);
sched_timer_id = timer_install(NULL, NULL, ticks, 0);
sched_timer_address = (uint32_t)&SH7305_TMU.TIMER[sched_timer_id].TCR;
sched_timer_intevt = 0x400 + (0x20 * sched_timer_id);
sched_timer_tstr_bit = 1 << sched_timer_id;
// Debug
kvram_clear();
printk(0, 0, "timer ID: %d", sched_timer_id);
printk(0, 1, "timer addr: %#x", sched_timer_address);
printk(0, 2, "timer event: %#x", sched_timer_intevt);
printk(0, 3, "timer TSTR: %#x", sched_timer_tstr_bit);
kvram_display();
DBG_WAIT;
// Start scheduler timer
timer_start(sched_timer_id);
}

11
src/kernel/scheduler/syscall/sys_exit.c

@ -0,0 +1,11 @@
#include <kernel/scheduler.h>
#include <kernel/util.h>
void sys_exit(int status)
{
kvram_clear();
printk(0, 0, "PROCESS EXIT SYSCALL !!!!");
printk(0, 0, "Wait manual reset...");
kvram_display();
while (1);
}

77
src/kernel/scheduler/syscall/sys_fexecve.c

@ -0,0 +1,77 @@
#include <kernel/process.h>
#include <kernel/scheduler.h>
#include <kernel/loader.h>
#include <kernel/atomic.h>
#include <kernel/util.h>
pid_t sys_fexecve(const char *pathname)
{
struct process *proc;
pid_t child_pid;
FILE *bin;
int error;
// Start atomic operation
atomic_start();
// Try create new process
proc = process_create(pathname);
if (proc == NULL)
{
kvram_clear();
printk(0, 0, "sys_fexecve: alloc error !");
kvram_display();
DBG_WAIT;
atomic_stop();
return (-1);
}
// Try to load binary into physical memory
proc->context.spc = (uint32_t)loader(pathname, proc);
if (proc->context.spc == 0x00000000)
{
kvram_clear();
printk(0, 0, "sys_fexecve: loader error !");
kvram_display();
DBG_WAIT;
process_free(proc);
atomic_stop();
return (-1);
}
// Debug
kvram_clear();
printk(0, 0, "New proc loaded !");
kvram_display();
DBG_WAIT;
// Add new process into task queue
error = sched_add_task(proc);
if (error != 0)
{
kvram_clear();
printk(0, 0, "sys_fexecve: scheduler error !");
kvram_display();
DBG_WAIT;
process_free(proc);
atomic_stop();
return (-1);
}
// Debug
printk(0, 1, "New proc sched added !");
kvram_display();
DBG_WAIT;
// Get child process PID
child_pid = process_get_pid(proc);
// Debug
printk(0, 2, "New proc PID = %#x !", child_pid);
kvram_display();
DBG_WAIT;
// Stop atomic operations
atomic_stop();
return (child_pid);
}

43
src/kernel/scheduler/syscall/sys_fork.c

@ -2,20 +2,41 @@
pid_t sys_fork(void)
{
extern process_t *process_current;
process_t **process_new;
pid_t process_pid;
extern struct process *process_current;
struct process *process_new;
pid_t process_new_pid;
// Check error
if (process_current == NULL)
return (-1);
// Get the new process slot.
process_new = &process_current->child;
while (*process_new != NULL)
process_new = &(*process_new)->next;
new_pid = process_alloc(&process_new);
if (new_pid != 0)
return (-1);
// Try to find new sheduler place.
process_pid = process_alloc(&(*process_new));
if (*process_new == NULL)
// Try to create user stack
process_new->memory.stack.size.user = process_current->;
process_new->memory.stack.user = (uint32_t)pm_alloc(process_new->memory.stack.size.user);
if (process_new->memory.stack.user == 0x00000000)
{
process_free(process_new);
return (-1);
// Initialize context.
}
// Try to create kernel stack
process_new->memory.stack.size.kernel = process_current->memory.stack.size.kernel;
process_new->memory.stack.kernel = (uint32_t)pm_alloc(process_new->memory.stack.size.kernel);
if (process_new->memory.stack.kernel == 0x00000000)
{
pm_free(process_new->memory.stack.user);
process_free(process_new);
return (-1);
}
//TODO: dump stack data
//TODO: dump code data
//TODO: Initialize context.
return (-1);
}*/

35
src/kernel/syscall/handler.c

@ -12,35 +12,36 @@ static void sys_test(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
DBG_WAIT;
}
static const void *sys_handler[15] = {
static const void *sys_handler[16] = {
// Kernel Test
sys_test, //restart
sys_test, // test
// Process
NULL, //exit
sys_waitpid, //waitpid
NULL, //exec
sys_exit, // exit
sys_fexecve, // fexecve
sys_waitpid, // waitpid
// VFS
sys_read, //read
sys_write, //write
sys_open, //open
sys_close, //close
sys_lseek, //lseek
sys_read, // read
sys_write, // write
sys_open, // open
sys_close, // close
sys_lseek, // lseek
// Display
kvram_display, //kvram_display
kvram_clear, //kvram_clear
kvram_print, //kvram_print
kvram_ascii, //kvram_ascii
kvram_reverse, //kvram_reverse
kvram_scroll //kvram_scroll
kvram_display, // kvram_display
kvram_clear, // kvram_clear
printk, // printk
kvram_ascii, // kvram_ascii
kvram_reverse, // kvram_reverse
kvram_scroll, // kvram_scroll
kvram_clr_str_area // kvram_clr_str_area
};
void *sys_get_handler(int sysno)
{
// Check sysno validity
if (sysno < 0 || sysno >= 14)
if (sysno < 0 || sysno >= 16)
return (0);
// DEBUG

1
src/kernel/syscall/syscall_pre.s

@ -31,6 +31,7 @@ _syscall_pre:
! Switch register bank and allow interrupt
! @note: user context has been saved
! during the `exception_handler_pre`
! TODO: do not allow interrupt ?
mov.l .sr_mask, r1 ! get SR mask for BL and IMASK
and r1, r0 ! set SR.BL = 0, SR.RB = 0 and SR.IMASK = 0b0000
ldc r0, sr ! update SR regsiter

59
src/kernel/util/kvram.c

@ -133,42 +133,49 @@ void kvram_reverse(int x, int y, int width, int height)
atomic_stop();
}
/* kvram_print() - Print string on Video RAM */
void kvram_print(int x, int y, char const *str)
/* kvram_clr_str_area() - Clear area based on kernel font size on Video RAM */
//FIXME: secure
void kvram_clr_str_area(int x, int y, int width, int height)
{
int default_pos_x;
int starting_x;
int i;
uint32_t vram_offset_y;
int cur_x;
int cur_y;
// Initialize part
i = -1;
starting_x = x;
x = x * (KERNEL_FONT_REAL_WIDTH + 1);
y = y * (KERNEL_FONT_REAL_HEIGHT + 1);
default_pos_x = x;
// Walk into string and display character by character
while (str[++i] != '\0')
width = width * (KERNEL_FONT_REAL_WIDTH + 1);
height = height * (KERNEL_FONT_REAL_HEIGHT + 1);
// Get VRAM offset
vram_offset_y = y << 2;
//DEbug
/*kvram_clear();
printk(0, 0, "kvram_clr_str_area debug !");
printk(0, 1, "x = %d", x);
printk(0, 2, "y = %d", y);
printk(0, 3, "width = %d", width);
printk(0, 4, "height = %d", height);
kvram_display();
DBG_WAIT;*/
// Clear area, pixel per pixel x____x
// TODO: update me !!!!
cur_y = -1;
while (++cur_y < height)
{
// New line
if (str[i] == '\n')
cur_x = -1;
while (++cur_x < width)
{
y = y + KERNEL_FONT_REAL_HEIGHT + 1;
x = default_pos_x;
continue;
}
// Horizontal tab
if (str[i] == '\t')
{
x = x / (KERNEL_FONT_REAL_WIDTH + 1);
x = (x + (4 - ((x - starting_x) & 3))) * (KERNEL_FONT_REAL_WIDTH + 1);
continue;
vram[((x + cur_x) >> 5) + vram_offset_y] &=
~(0x80000000 >> ((x + cur_x) & 31));
}
// Default, display character
font_draw(x, y, str[i]);
x = x + KERNEL_FONT_REAL_WIDTH + 1;
// update internal counter
vram_offset_y = vram_offset_y + 4;
}
}
/* kvram_ascii() - Draw ASCII character into Video RAM */

72
src/kernel/util/timer.c

@ -1,10 +1,39 @@
#include <kernel/util.h>
#include <kernel/hardware/tmu.h>
#include <kernel/devices/timer.h>
#include <kernel/atomic.h>