Hi,
apologies again.

I am not familiar with cvs so I have used the diff command between an
original sys folder and mine.

I am attaching the diff file and two files to be put in sys/kern. Sorry but
the diff
command did not include the content of the two files in the diff itself.

Please notice that this is not code that is intended to be put into the
openbsd kernel,
as it would probably not be interesting to the general users.

What I am doing here is to have a syscall that stops the scheduler on 3 of
the 4 cores,
runs my own code on those while the calling process runs on the other core
and restarts
scheduling on the 3 cores when the process terminates.
The shared memory is used for the 3 cores to communicate with the process.
I know that it might sound crazy to you but it does make a lot of sense for
what
I am trying to achieve.

Regarding the mapping, I hope that it works well enough even with
reordering issues and other stuff.
It does for the example I am sending and I don't need much more than that.

What I was flagging is just that sometimes uvm_map returns an address that
is not
aligned to PAGE_SIZE ( I printed it out and it has 0x004 in the lower 12
bits). On the
other hand uvm_unmap has an assertion that panics if the address passed to
it is not
page aligned. I believe that there could be a bug somewhere.

In previous runs I was getting constantly an address which is not aligned
but now
I get an address that is aligned.

Best :-)
Alessandro

On Sat, Apr 24, 2021 at 2:32 AM Theo de Raadt <dera...@openbsd.org> wrote:

> Alessandro Pistocchi <apukbusin...@gmail.com> wrote:
>
> > During the syscall I allocate some memory that I want to share between
> the
> > kernel and the calling process.
>
> When you get the mapping working, it will not work as well as you like.
>
> Compiler re-ordering of writes & reads, caches, write buffers, and other
> details such as non-TSO will creat problems, meaning you'll need very
> careful
> data-structure, and great care with co-dependent fields, otherwise one side
> can fool the other.
>
> That is why the copyin/copyout approach is used as a high-level
> serializing-forcing
> primitive in most operating systems.
>
> But since you don't show your whole diff.. I suspect this is a waste of
> time.
>
struct uvm_object *game_uvm_object;

void game_mode_create_shared_memory_region(struct proc *p) {
	game_uvm_object = uao_create(game_memory_size, 0);
	if(!game_uvm_object) return;

	// TODO(ale): make sure that this memory cannot be swapped out

	uao_reference(game_uvm_object);
	if(uvm_map(kernel_map, (vaddr_t *)&game_memory, round_page(game_memory_size), game_uvm_object,
		    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
		    MAP_INHERIT_SHARE, MADV_NORMAL, 0))) {
		uao_detach(game_uvm_object);
		game_uvm_object = 0;
		return;
	}

	uao_reference(game_uvm_object);
	if(uvm_map(&p->p_vmspace->vm_map, (vaddr_t *)&game_memory_in_proc_space, round_page(game_memory_size), game_uvm_object,
		    0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
		    MAP_INHERIT_NONE, MADV_NORMAL, 0))) {
		// TODO(ale): the kernel mapping returns an address for game_memory that is 4 bytes more than page aligned. This panics.
		uvm_unmap(kernel_map, trunc_page((vaddr_t)game_memory), round_page((vaddr_t)game_memory + game_memory_size));
		game_memory = 0;
		uao_detach(game_uvm_object);
		uao_detach(game_uvm_object);
		game_uvm_object = 0;
		return;
	}

	game_mode_proc = p;

}

void game_mode_free_shared_memory_region(void) {
	if(game_memory_in_proc_space)uvm_unmap(&game_mode_proc->p_vmspace->vm_map, trunc_page((vaddr_t)game_memory_in_proc_space),
		round_page((vaddr_t)game_memory_in_proc_space + game_memory_size));
	// TODO(ale): the kernel mapping returns an address for game_memory that is 4 bytes more than page aligned. This panics.
	if(game_memory)uvm_unmap(kernel_map, trunc_page((vaddr_t)game_memory), round_page((vaddr_t)game_memory + game_memory_size));
	if(game_uvm_object){
		uao_detach(game_uvm_object);
		uao_detach(game_uvm_object);
	}
	game_memory_in_proc_space = game_memory = 0;
	game_uvm_object = 0;
}

// static inline void *phisical_from_virtual(struct proc *p, void *va) {
// 	paddr_t pa;
// 	vaddr_t faddr = trunc_page((vaddr_t)va), off = ((vaddr_t)va) - faddr;
// 	if (pmap_extract(vm_map_pmap(&p->p_vmspace->vm_map), faddr, &pa) == FALSE) panic("vmapbuf: null page frame");
// 	return (void *)(pa+(paddr_t)off);
// }
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/systm.h>
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/atomic.h>
#include <sys/errno.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/syscallargs.h>
#include <uvm/uvm_extern.h>
#include <machine/pmap.h>
#include <sys/malloc.h>
#include <sys/param.h> 
#include <uvm/uvm.h>

#define VBLANK_THREAD 		1
#define AUDIO_THREAD 		2
#define INPUT_THREAD 		3

void *game_memory;
void *game_memory_in_proc_space;
vsize_t game_memory_size;

void sched_start_secondary_cpus(void);
void sched_stop_secondary_cpus(void);

void game_mode_create_shared_memory_region(struct proc *p);
void game_mode_free_shared_memory_region(void);

volatile int game_mode_on;
struct proc *game_mode_proc;
volatile int game_mode_number_of_threads;

int sys_start_game_mode(struct proc *p, void *v, register_t *retval) {

	if(game_mode_on || game_mode_proc) return EAGAIN;
	
	struct sys_start_game_mode_args args = *((struct sys_start_game_mode_args *)v);
	game_memory_size = (vsize_t)SCARG(&args, memory_size);
	if(game_memory_size == 0) return EINVAL;
	game_memory_size = round_page(game_memory_size);

	game_mode_create_shared_memory_region(p);
	if(!game_memory_in_proc_space || !game_memory || !game_mode_proc ) { game_memory = game_memory_in_proc_space = 0; game_mode_proc = 0; return ENOMEM; }	

	*retval = (register_t)(game_memory_in_proc_space);

	game_mode_on = 1;
	game_mode_number_of_threads = 0;
	sched_stop_secondary_cpus();
	KASSERT(CPU_IS_PRIMARY(curcpu()));
	return (0);

}

void stop_game_mode(void) {
	KASSERT(CPU_IS_PRIMARY(curcpu()));
	if(!game_mode_on) return;
	// ensure all threads are started before exiting - THEY EXIT ONLY WHEN game_mode_on is 0
	while(game_mode_number_of_threads<INPUT_THREAD);
	game_mode_on = 0;
	// ensure all threads are stopped before exiting
	while(game_mode_number_of_threads);
	// it's safe to free here as the threads are all stopped and so is the user program
	game_mode_free_shared_memory_region();
	game_mode_proc = 0;
	sched_start_secondary_cpus();
}

void game_mode_start_vblank_thread();
void game_mode_start_audio_thread();
void game_mode_start_input_thread();

void game_mode_exec(void) {
	KASSERT(!CPU_IS_PRIMARY(curcpu()));
	int thread_to_create = atomic_inc_int_nv(&game_mode_number_of_threads);
	switch(thread_to_create) {
		case VBLANK_THREAD:
		{
			game_mode_start_vblank_thread();
			atomic_dec_int_nv(&game_mode_number_of_threads);
		}
		break;
		case AUDIO_THREAD:
		{
			game_mode_start_audio_thread();
			atomic_dec_int_nv(&game_mode_number_of_threads);
		}
		break;
		case INPUT_THREAD:
		{
			game_mode_start_input_thread();
			atomic_dec_int_nv(&game_mode_number_of_threads);
		}
		break;
	}
}

void game_mode_start_vblank_thread(){disable_interrupts();while(game_mode_on){};enable_interrupts();printf("vblank exiting\n");}
void game_mode_start_audio_thread(){disable_interrupts();*(char *)game_memory++ = 'A';*(char *)game_memory++ = 'l';*(char *)game_memory++ = 'e';*(char *)game_memory++ = 0;while(game_mode_on){};enable_interrupts();printf("audio exiting\n");}
void game_mode_start_input_thread(){disable_interrupts();while(game_mode_on){};enable_interrupts();printf("input exiting\n");}

#include "start_game_mode_shared_memory.c"

Attachment: sys.diff
Description: Binary data

Reply via email to