waterbox: add guard pages to libco stacks
This commit is contained in:
parent
8a24960cce
commit
626de2d7c8
|
@ -42,6 +42,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
|
|
||||||
private class Bin
|
private class Bin
|
||||||
{
|
{
|
||||||
|
public const MemoryBlock.Protection _FreeProt = (MemoryBlock.Protection)255;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// first page# in this bin, inclusive
|
/// first page# in this bin, inclusive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -62,11 +64,11 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (byte)Protection == 255;
|
return Protection == _FreeProt;
|
||||||
}
|
}
|
||||||
set
|
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);
|
var ds = Memory.GetStream(ret, oldSize, true);
|
||||||
ss.CopyTo(ds);
|
ss.CopyTo(ds);
|
||||||
Memory.Protect(ret, oldSize, oldStartBin.Protection);
|
Memory.Protect(ret, oldSize, oldStartBin.Protection);
|
||||||
UnmapPagesInternal(oldStartPage, oldNumPages, oldStartBin);
|
ProtectPagesInternal(oldStartPage, oldNumPages, oldStartBin, Bin._FreeProt);
|
||||||
//EnsureUsedInternal();
|
//EnsureUsedInternal();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -276,7 +278,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
// shrink in place
|
// shrink in place
|
||||||
var s = GetBinForStartPage(newEndPage);
|
var s = GetBinForStartPage(newEndPage);
|
||||||
UnmapPagesInternal(newEndPage, oldEndPage - newEndPage, s);
|
ProtectPagesInternal(newEndPage, oldEndPage - newEndPage, s, Bin._FreeProt);
|
||||||
//EnsureUsedInternal();
|
//EnsureUsedInternal();
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
@ -302,14 +304,34 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
|
if (GetBinForEndPageEnsureAllocated(endPage, startBin) == null)
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// frees some pages. assumes they are all allocated
|
/// frees or changes the protection on some pages. assumes they are all allocated
|
||||||
/// </summary>
|
/// </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
|
// 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)
|
if (freeBin.StartPage != startPage)
|
||||||
{
|
{
|
||||||
freeBin.Cleave(startPage - freeBin.StartPage);
|
freeBin.Cleave(startPage - freeBin.StartPage);
|
||||||
|
freeBin.Next.Protection = freeBin.Protection;
|
||||||
freeBin = freeBin.Next;
|
freeBin = freeBin.Next;
|
||||||
}
|
}
|
||||||
freeBin.Free = true;
|
MemoryBlock.Protection lastEaten = freeBin.Protection;
|
||||||
MemoryBlock.Protection lastEaten = MemoryBlock.Protection.None;
|
|
||||||
while (freeBin.EndPage < endPage)
|
while (freeBin.EndPage < endPage)
|
||||||
{
|
{
|
||||||
freeBin.PageCount += freeBin.Next.PageCount;
|
freeBin.PageCount += freeBin.Next.PageCount;
|
||||||
|
@ -332,11 +354,19 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
freeBin.Next.Protection = lastEaten;
|
freeBin.Next.Protection = lastEaten;
|
||||||
}
|
}
|
||||||
|
freeBin.Protection = prot;
|
||||||
freeBin.ApplyProtection(Memory);
|
freeBin.ApplyProtection(Memory);
|
||||||
|
|
||||||
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
|
var totalSize = ((ulong)numPages) << WaterboxUtils.PageShift;
|
||||||
Used -= totalSize;
|
if (prot == Bin._FreeProt)
|
||||||
Console.WriteLine($"Freed {totalSize} bytes on {Name}, utilization {Used}/{Memory.Size} ({100.0 * Used / Memory.Size:0.#}%)");
|
{
|
||||||
|
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();
|
//EnsureUsedInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -456,6 +456,25 @@ namespace BizHawk.Emulation.Cores.Waterbox
|
||||||
{
|
{
|
||||||
return _parent._mmapheap.Unmap((ulong)address, (ulong)size) ? 0 : -1;
|
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>
|
/// <summary>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
CC = x86_64-nt64-midipix-gcc
|
CC = x86_64-nt64-midipix-gcc
|
||||||
AS = nasm
|
AS = nasm
|
||||||
|
|
||||||
CCFLAGS:= -Wall -O3
|
CCFLAGS:= -Wall -O3 -std=c99
|
||||||
ASFLAGS:= -f elf64
|
ASFLAGS:= -f elf64
|
||||||
|
|
||||||
TARGET = libco.so
|
TARGET = libco.so
|
||||||
|
@ -21,25 +21,25 @@ AOBJS:=$(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_AOBJS))
|
||||||
|
|
||||||
$(OBJ_DIR)/%.c.o: %.c
|
$(OBJ_DIR)/%.c.o: %.c
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(CC) -c -o $@ $< $(CCFLAGS)
|
@$(CC) -c -o $@ $< $(CCFLAGS)
|
||||||
|
|
||||||
$(OBJ_DIR)/%.s.o: %.s
|
$(OBJ_DIR)/%.s.o: %.s
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(AS) $(ASFLAGS) -o $@ $<
|
@$(AS) $(ASFLAGS) -o $@ $<
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
|
|
||||||
$(TARGET): $(OBJS) $(AOBJS)
|
$(TARGET): $(OBJS) $(AOBJS)
|
||||||
$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
|
@$(CC) -o $@ $(LDFLAGS) $(CCFLAGS) $(OBJS) $(AOBJS)
|
||||||
mv $(TARGET) $(TARGET).in
|
@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
|
@strip $(TARGET).in -o $(TARGET) -R /4 -R /14 -R /29 -R /41 -R /55 -R /67 -R /78 -R /89 -R /104
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJ_DIR)
|
@rm -rf $(OBJ_DIR)
|
||||||
rm -f $(TARGET).in
|
@rm -f $(TARGET).in
|
||||||
rm -f $(TARGET)
|
@rm -f $(TARGET)
|
||||||
|
|
||||||
#install:
|
#install:
|
||||||
# $(CP) $(TARGET) $(DEST_$(ARCH))
|
# $(CP) $(TARGET) $(DEST_$(ARCH))
|
||||||
|
|
|
@ -7,76 +7,94 @@
|
||||||
#define LIBCO_C
|
#define LIBCO_C
|
||||||
#include "libco.h"
|
#include "libco.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static long long co_active_buffer[64];
|
static long long co_active_buffer[64];
|
||||||
static cothread_t co_active_handle = 0;
|
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);
|
// align up to 4k
|
||||||
if (ret)
|
*size = (*size + 16384 + 4095) & ~4095;
|
||||||
{
|
|
||||||
*(size_t*)ret = size;
|
uint64_t* ptr = mmap(NULL, *size,
|
||||||
return ret + 16;
|
PROT_READ | PROT_WRITE, MAP_ANONYMOUS, -1, 0);
|
||||||
}
|
if (ptr == (uint64_t*)(-1))
|
||||||
return NULL;
|
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;
|
uint64_t* ptr = (uint64_t*)p;
|
||||||
size_t size = *(size_t*)original + 16;
|
if (mprotect(ptr + 512, 512 * 3 * sizeof(uint64_t), PROT_READ | PROT_WRITE) != 0)
|
||||||
memset(original, 0, size);
|
abort();
|
||||||
free(original);
|
uint64_t size = ptr[512];
|
||||||
|
memset(p, 0, size);
|
||||||
|
if (munmap(ptr, size) != 0)
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void co_swap(cothread_t, cothread_t);
|
extern void co_swap(cothread_t, cothread_t);
|
||||||
|
|
||||||
static void crash() {
|
static void crash()
|
||||||
assert(0); /* called only if cothread_t entrypoint returns */
|
{
|
||||||
|
assert(0); /* called only if cothread_t entrypoint returns */
|
||||||
}
|
}
|
||||||
|
|
||||||
void co_clean() {
|
void co_clean()
|
||||||
memset(co_active_buffer, 0, sizeof(co_active_buffer));
|
{
|
||||||
|
memset(co_active_buffer, 0, sizeof(co_active_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
cothread_t co_active() {
|
cothread_t co_active()
|
||||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
{
|
||||||
return co_active_handle;
|
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 co_create(unsigned int sz, void (*entrypoint)(void))
|
||||||
cothread_t handle;
|
{
|
||||||
if(!co_active_handle) co_active_handle = &co_active_buffer;
|
cothread_t handle;
|
||||||
size += 512; /* allocate additional space for storage */
|
if (!co_active_handle)
|
||||||
size &= ~15; /* align stack to 16-byte boundary */
|
co_active_handle = &co_active_buffer;
|
||||||
|
|
||||||
if(handle = (cothread_t)smalloc(size)) {
|
uint64_t size = sz;
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
void co_delete(cothread_t handle)
|
||||||
sfree(handle);
|
{
|
||||||
|
free_thread(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void co_switch(cothread_t 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);
|
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.
Loading…
Reference in New Issue