waterbox: add guard pages to libco stacks

This commit is contained in:
nattthebear 2017-06-11 20:05:35 -04:00
parent 8a24960cce
commit 626de2d7c8
8 changed files with 138 additions and 65 deletions

View File

@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
private class Bin
{
public const MemoryBlock.Protection _FreeProt = (MemoryBlock.Protection)255;
/// <summary>
/// first page# in this bin, inclusive
/// </summary>
@ -62,11 +64,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
get
{
return (byte)Protection == 255;
return Protection == _FreeProt;
}
set
{
Protection = value ? (MemoryBlock.Protection)255 : MemoryBlock.Protection.None;
Protection = value ? _FreeProt : MemoryBlock.Protection.None;
}
}
@ -263,7 +265,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
var ds = Memory.GetStream(ret, oldSize, true);
ss.CopyTo(ds);
Memory.Protect(ret, oldSize, oldStartBin.Protection);
UnmapPagesInternal(oldStartPage, oldNumPages, oldStartBin);
ProtectPagesInternal(oldStartPage, oldNumPages, oldStartBin, Bin._FreeProt);
//EnsureUsedInternal();
return ret;
}
@ -276,7 +278,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
// shrink in place
var s = GetBinForStartPage(newEndPage);
UnmapPagesInternal(newEndPage, oldEndPage - newEndPage, s);
ProtectPagesInternal(newEndPage, oldEndPage - newEndPage, s, Bin._FreeProt);
//EnsureUsedInternal();
return start;
}
@ -302,14 +304,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
return false;
UnmapPagesInternal(startPage, numPages, startBin);
ProtectPagesInternal(startPage, numPages, startBin, Bin._FreeProt);
return true;
}
public bool Protect(ulong start, ulong size, MemoryBlock.Protection prot)
{
// TODO: lots of copy paste here
if (start < Memory.Start || start + size > Memory.End)
return false;
if (size == 0)
return true;
var startPage = GetPage(start);
var numPages = WaterboxUtils.PagesNeeded(size);
var endPage = startPage + numPages;
// to change protection, the entire area must currently be mapped
var startBin = GetBinForStartPage(startPage);
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
return false;
ProtectPagesInternal(startPage, numPages, startBin, prot);
return true;
}
/// <summary>
/// frees some pages. assumes they are all allocated
/// frees or changes the protection on some pages. assumes they are all allocated
/// </summary>
private void UnmapPagesInternal(int startPage, int numPages, Bin startBin)
private void ProtectPagesInternal(int startPage, int numPages, Bin startBin, MemoryBlock.Protection prot)
{
// from the various paths we took to get here, we must be unmapping at least one page
@ -318,10 +340,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
if (freeBin.StartPage != startPage)
{
freeBin.Cleave(startPage - freeBin.StartPage);
freeBin.Next.Protection = freeBin.Protection;
freeBin = freeBin.Next;
}
freeBin.Free = true;
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
MemoryBlock.Protection lastEaten = freeBin.Protection;
while (freeBin.EndPage < endPage)
{
freeBin.PageCount += freeBin.Next.PageCount;
@ -332,11 +354,19 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
freeBin.Next.Protection = lastEaten;
}
freeBin.Protection = prot;
freeBin.ApplyProtection(Memory);
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
Used -= totalSize;
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
if (prot == Bin._FreeProt)
{
Used -= totalSize;
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
}
else
{
Console.WriteLine($"Set protection for {totalSize} bytes on {Name} to {prot}");
}
//EnsureUsedInternal();
}

View File

@ -456,6 +456,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : -1;
}
[BizExport(CallingConvention.Cdecl, EntryPoint = "n10")]
public int MProtect(UIntPtr address, UIntPtr size, int prot)
{
MemoryBlock.Protection mprot;
switch (prot)
{
case 0: mprot = MemoryBlock.Protection.None; break;
default:
case 6: // W^X
case 7: // W^X
case 4: // exec only????
case 2: return -1; // write only????
case 3: mprot = MemoryBlock.Protection.RW; break;
case 1: mprot = MemoryBlock.Protection.R; break;
case 5: mprot = MemoryBlock.Protection.RX; break;
}
return _parent._mmapheap.Protect((ulong)address, (ulong)size, mprot) ? 0 : -1;
}
}
/// <summary>

Binary file not shown.

Binary file not shown.

6
waterbox/libco/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
// Place your settings in this file to overwrite default and user settings.
{
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"editor.tabSize": 4
}

View File

@ -1,7 +1,7 @@
CC = x86_64-nt64-midipix-gcc
AS = nasm
CCFLAGS:= -Wall -O3
CCFLAGS:= -Wall -O3 -std=c99
ASFLAGS:= -f elf64
TARGET = libco.so
@ -21,25 +21,25 @@ AOBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_AOBJS))
$(OBJ_DIR)/%.c.o: %.c
@mkdir -p $(@D)
$(CC) -c -o $@ $< $(CCFLAGS)
@$(CC) -c -o $@ $< $(CCFLAGS)
$(OBJ_DIR)/%.s.o: %.s
@mkdir -p $(@D)
$(AS) $(ASFLAGS) -o $@ $<
@$(AS) $(ASFLAGS) -o $@ $<
all: $(TARGET)
.PHONY: clean all
$(TARGET): $(OBJS) $(AOBJS)
$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
mv $(TARGET) $(TARGET).in
strip $(TARGET).in -o $(TARGET) -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
@mv $(TARGET) $(TARGET).in
@strip $(TARGET).in -o $(TARGET) -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
clean:
rm -rf $(OBJ_DIR)
rm -f $(TARGET).in
rm -f $(TARGET)
@rm -rf $(OBJ_DIR)
@rm -f $(TARGET).in
@rm -f $(TARGET)
#install:
# $(CP) $(TARGET) $(DEST_$(ARCH))

View File

@ -7,76 +7,94 @@
#define LIBCO_C
#include "libco.h"
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/mman.h>
static long long co_active_buffer[64];
static cothread_t co_active_handle = 0;
static void* smalloc(size_t size)
// allocations are 16k larger than asked for,
// and include guard space between the stack and the storage
static void* alloc_thread(size_t* size)
{
char* ret = malloc(size + 16);
if (ret)
{
*(size_t*)ret = size;
return ret + 16;
}
return NULL;
// align up to 4k
*size = (*size + 16384 + 4095) & ~4095;
uint64_t* ptr = mmap(NULL, *size,
PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
if (ptr == (uint64_t*)(-1))
return NULL;
ptr[512] = *size;
for (int i = 513; i < 2048; i++)
ptr[i] = 0xdeadbeefdeadbeef;
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_NONE) != 0)
abort();
return ptr;
}
static void sfree(void* ptr)
static void free_thread(void* p)
{
char* original = (char*)ptr - 16;
size_t size = *(size_t*)original + 16;
memset(original, 0, size);
free(original);
uint64_t* ptr = (uint64_t*)p;
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_READ | PROT_WRITE) != 0)
abort();
uint64_t size = ptr[512];
memset(p, 0, size);
if (munmap(ptr, size) != 0)
abort();
}
extern void co_swap(cothread_t, cothread_t);
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
static void crash()
{
assert(0); /* called only if cothread_t entrypoint returns */
}
void co_clean() {
memset(co_active_buffer, 0, sizeof(co_active_buffer));
void co_clean()
{
memset(co_active_buffer, 0, sizeof(co_active_buffer));
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
cothread_t co_active()
{
if (!co_active_handle)
co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 512; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
cothread_t co_create(unsigned int sz, void (*entrypoint)(void))
{
cothread_t handle;
if (!co_active_handle)
co_active_handle = &co_active_buffer;
if(handle = (cothread_t)smalloc(size)) {
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
*--p = (long long)crash; /* crash if entrypoint returns */
*--p = (long long)entrypoint; /* start of function */
*(long long*)handle = (long long)p; /* stack pointer */
}
uint64_t size = sz;
return handle;
if (handle = (cothread_t)alloc_thread(&size))
{
uint64_t* p = (uint64_t*)((char*)handle + size); // seek to top of stack
*--p = (uint64_t)crash; /* crash if entrypoint returns */
*--p = (uint64_t)entrypoint; /* start of function */
*(uint64_t*)handle = (uint64_t)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
sfree(handle);
void co_delete(cothread_t handle)
{
free_thread(handle);
}
void co_switch(cothread_t handle) {
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
void co_switch(cothread_t handle)
{
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#ifdef __cplusplus
}
#endif

Binary file not shown.