mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-24 23:53:04 +00:00
Add heapblock and dlmalloc for managing memory
heapblock is a simple `sbrk` style implementation, also useful as an "endless" decompression buffer. dlmalloc is used on top as a malloc implementation. This also changes how the Python side manages its heap. We still use a python-side malloc implementation (since this is faster), and we put the Python heap at the m1n1 heap + 128MB, without allocating it. Hopefully this should never step on anything m1n1 neads, and avoids having to manage freeing across Python script calls. Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
f3d0a58f42
commit
986c6730e9
16 changed files with 6595 additions and 23 deletions
121
3rdparty_licenses/LICENSE.CC0
Normal file
121
3rdparty_licenses/LICENSE.CC0
Normal file
|
@ -0,0 +1,121 @@
|
|||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
7
Makefile
7
Makefile
|
@ -16,9 +16,12 @@ MINILZLIB_OBJECTS := $(patsubst %,minilzlib/%, \
|
|||
TINF_OBJECTS := $(patsubst %,tinf/%, \
|
||||
adler32.o crc32.o tinfgzip.o tinflate.o tinfzlib.o)
|
||||
|
||||
DLMALLOC_OBJECTS := dlmalloc/malloc.o
|
||||
|
||||
OBJECTS := adt.o bootlogo_128.o bootlogo_256.o chickens.o exception.o exception_asm.o fb.o \
|
||||
main.o memory.o memory_asm.o proxy.o smp.o start.o startup.o string.o uart.o uartproxy.o \
|
||||
utils.o utils_asm.o vsprintf.o wdt.o $(MINILZLIB_OBJECTS) $(TINF_OBJECTS)
|
||||
heapblock.o main.o memory.o memory_asm.o proxy.o smp.o start.o startup.o string.o uart.o \
|
||||
uartproxy.o utils.o utils_asm.o vsprintf.o wdt.o $(MINILZLIB_OBJECTS) $(TINF_OBJECTS) \
|
||||
$(DLMALLOC_OBJECTS)
|
||||
|
||||
DTS := apple-j274.dts
|
||||
|
||||
|
|
|
@ -38,3 +38,10 @@ m1n1 embeds portions taken from
|
|||
[BSD](3rdparty_licenses/LICENSE.BSD-3.arm) licensed and copyright:
|
||||
|
||||
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
|
||||
|
||||
m1n1 embeds [Doug Lea's malloc](ftp://gee.cs.oswego.edu/pub/misc/malloc.c) (dlmalloc), which is in
|
||||
the public domain ([CC0](3rdparty_licenses/LICENSE.CC0)).
|
||||
|
||||
m1n1 embeds portions of [PDCLib](https://github.com/DevSolar/pdclib), which is in the public
|
||||
domain ([CC0](3rdparty_licenses/LICENSE.CC0).
|
||||
|
||||
|
|
8
m1n1.ld
8
m1n1.ld
|
@ -5,6 +5,8 @@ _va_base = 0xFFFFFE0007004000;
|
|||
|
||||
_stack_size = 0x20000;
|
||||
|
||||
_max_payload_size = 64*1024*1024;
|
||||
|
||||
/* We are actually relocatable */
|
||||
. = 0;
|
||||
|
||||
|
@ -106,9 +108,9 @@ SECTIONS {
|
|||
LONG(0x444C5950); /* segmname = "PYLD" */
|
||||
. += 12;
|
||||
QUAD(_end + _va_off); /* vmaddr */
|
||||
QUAD(64*1024*1024); /* vmsize */
|
||||
QUAD(_max_payload_size); /* vmsize */
|
||||
QUAD(_file_end - _base); /* fileoff */
|
||||
QUAD(64*1024*1024); /* filesize */
|
||||
QUAD(_max_payload_size); /* filesize */
|
||||
LONG(PROT_READ | PROT_WRITE); /* maxprot */
|
||||
LONG(PROT_READ | PROT_WRITE); /* initprot */
|
||||
LONG(0); /* nsects */
|
||||
|
@ -169,6 +171,8 @@ SECTIONS {
|
|||
} :data
|
||||
_data_size = . - _data_start;
|
||||
_end = .;
|
||||
_payload_start = .;
|
||||
_payload_end = . + _max_payload_size;
|
||||
|
||||
.symtab 0 : { *(.symtab) }
|
||||
.strtab 0 : { *(.strtab) }
|
||||
|
|
|
@ -1,25 +1,19 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import serial, os, struct, sys, time
|
||||
from proxy import *
|
||||
from tgtypes import *
|
||||
|
||||
uartdev = os.environ.get("M1N1DEVICE", "/dev/ttyUSB0")
|
||||
usbuart = serial.Serial(uartdev, 115200)
|
||||
|
||||
iface = UartInterface(usbuart, debug=False)
|
||||
proxy = M1N1Proxy(iface, debug=False)
|
||||
|
||||
proxy.set_baud(1500000)
|
||||
from setup import *
|
||||
|
||||
payload = open(sys.argv[1], "rb").read()
|
||||
|
||||
base = proxy.get_base()
|
||||
ba_addr = proxy.get_bootargs()
|
||||
try:
|
||||
# Try to use the m1n1 heap to avoid wasting 128MB RAM on every load
|
||||
new_base = p.memalign(0x10000, len(payload))
|
||||
except:
|
||||
# Fall back to proxy heap, which will be at the right place in old versions
|
||||
new_base = u.memalign(0x10000, len(payload))
|
||||
|
||||
ba = iface.readstruct(ba_addr, BootArgs)
|
||||
|
||||
new_base = base + ((ba.top_of_kernel_data + 0xffff) & ~0xffff) - ba.phys_base
|
||||
# FIXME: this will currently still waste the whole m1n1 size including payload area (64+MB) on each
|
||||
# chainload. The best way to fix this is to support in-place chainloading, which has other
|
||||
# advantages.
|
||||
|
||||
print("Loading %d bytes to 0x%x" % (len(payload), new_base))
|
||||
|
||||
|
@ -29,7 +23,7 @@ entry = new_base + 0x4800
|
|||
|
||||
print("Jumping to 0x%x" % entry)
|
||||
|
||||
proxy.reboot(entry, ba_addr)
|
||||
p.reboot(entry, u.ba_addr)
|
||||
|
||||
iface.nop()
|
||||
print("Proxy is alive again")
|
||||
|
|
|
@ -308,6 +308,11 @@ class M1N1Proxy:
|
|||
P_SMP_CALL = 0x501
|
||||
P_SMP_CALL_SYNC = 0x502
|
||||
|
||||
P_HEAPBLOCK_ALLOC = 0x600
|
||||
P_MALLOC = 0x601
|
||||
P_MEMALIGN = 0x602
|
||||
P_FREE = 0x602
|
||||
|
||||
def __init__(self, iface, debug=False):
|
||||
self.debug = debug
|
||||
self.iface = iface
|
||||
|
@ -517,6 +522,15 @@ class M1N1Proxy:
|
|||
raise ValueError("Too many arguments")
|
||||
return self.request(self.P_SMP_CALL_SYNC, cpu, addr, *args)
|
||||
|
||||
def heapblock_alloc(self, size):
|
||||
return self.request(self.P_HEAPBLOCK_ALLOC, size)
|
||||
def malloc(self, size):
|
||||
return self.request(self.P_MALLOC, size)
|
||||
def memalign(self, align, size):
|
||||
return self.request(self.P_MEMALIGN, align, size)
|
||||
def free(self, ptr):
|
||||
self.request(self.P_FREE, ptr)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import serial
|
||||
uartdev = os.environ.get("M1N1DEVICE", "/dev/ttyUSB0")
|
||||
|
|
|
@ -40,9 +40,22 @@ class ProxyUtils(object):
|
|||
self.ba_addr = p.get_bootargs()
|
||||
|
||||
self.ba = self.iface.readstruct(self.ba_addr, BootArgs)
|
||||
self._scratch = self.base + ((self.ba.top_of_kernel_data + 0xffff) & ~0xffff) - self.ba.phys_base
|
||||
|
||||
self.heap = malloc.Heap(self._scratch, self._scratch + 0x1000000)
|
||||
# We allocate a 128MB heap, 128MB after the m1n1 heap, without telling it about it.
|
||||
# This frees up from having to coordinate memory management or free stuff after a Python
|
||||
# script runs, at the expense that if m1n1 ever uses more than 128MB of heap it will
|
||||
# clash with Python (m1n1 will normally not use *any* heap when running proxy ops though,
|
||||
# except when running very high-level operations like booting a kernel, so this should be
|
||||
# OK).
|
||||
self.heap_size = 128 * 1024 * 1024
|
||||
try:
|
||||
self.heap_base = p.heapblock_alloc(0)
|
||||
except ProxyRemoteError:
|
||||
# Compat with versions that don't have heapblock yet
|
||||
self.heap_base = (self.base + ((self.ba.top_of_kernel_data + 0xffff) & ~0xffff) -
|
||||
self.ba.phys_base)
|
||||
self.heap_base += 128 * 1024 * 1024 # We leave 128MB for m1n1 heap
|
||||
self.heap = malloc.Heap(self.heap_base, self.heap_base + self.heap_size)
|
||||
|
||||
self.malloc = self.heap.malloc
|
||||
self.memalign = self.heap.memalign
|
||||
|
|
6282
src/dlmalloc/malloc.c
Normal file
6282
src/dlmalloc/malloc.c
Normal file
File diff suppressed because it is too large
Load diff
33
src/dlmalloc/malloc_config.h
Normal file
33
src/dlmalloc/malloc_config.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "../heapblock.h"
|
||||
#include "../string.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#define HAVE_MORECORE 1
|
||||
#define HAVE_MMAP 0
|
||||
#define MORECORE sbrk
|
||||
// This is optimal; dlmalloc copes with other users of sbrk/MORECORE gracefully, and heapblock
|
||||
// guarantees contiguous returns if called consecutively.
|
||||
#define MORECORE_CONTIGUOUS 1
|
||||
#define MALLOC_ALIGNMENT 16
|
||||
#define ABORT panic("dlmalloc: internal error\n")
|
||||
#define NO_MALLINFO 1
|
||||
#define NO_MALLOC_STATS 1
|
||||
#define malloc_getpagesize 16384
|
||||
#define LACKS_UNISTD_H 1
|
||||
#define LACKS_FCNTL_H 1
|
||||
#define LACKS_SYS_PARAM_H 1
|
||||
#define LACKS_SYS_MMAN_H 1
|
||||
#define LACKS_STRINGS_H 1
|
||||
#define LACKS_STRING_H 1
|
||||
#define LACKS_STDLIB_H 1
|
||||
#define LACKS_SCHED_H 1
|
||||
#define LACKS_TIME_H 1
|
||||
#define MALLOC_FAILURE_ACTION panic("dlmalloc: out of memory\n");
|
||||
|
||||
static void *sbrk(intptr_t inc)
|
||||
{
|
||||
if (inc < 0)
|
||||
return (void *)-1;
|
||||
|
||||
return heapblock_alloc(inc);
|
||||
}
|
49
src/heapblock.c
Normal file
49
src/heapblock.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "heapblock.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "xnuboot.h"
|
||||
|
||||
/*
|
||||
* This is a non-freeing allocator, used as a backend for malloc and for uncompressing data.
|
||||
*
|
||||
* Allocating 0 bytes is allowed, and guarantees "infinite" (until the end of RAM) space is
|
||||
* available at the returned pointer as long as no other malloc/heapblock calls occur, which is
|
||||
* useful as a buffer for unknown-length uncompressed data. A subsequent call with a size will then
|
||||
* actually reserve the block.
|
||||
*/
|
||||
|
||||
static void *heap_base;
|
||||
|
||||
void heapblock_init(void)
|
||||
{
|
||||
void *top_of_kernel_data = (void *)cur_boot_args.top_of_kernel_data;
|
||||
void *payload_end = _payload_end;
|
||||
|
||||
if (payload_end > top_of_kernel_data)
|
||||
heap_base = payload_end; // Chainloaded, we are last in RAM
|
||||
else
|
||||
heap_base = top_of_kernel_data; // Loaded by iBoot, there is data after us in RAM
|
||||
|
||||
heapblock_alloc(0); // align base
|
||||
|
||||
printf("Heap base: %p\n", heap_base);
|
||||
}
|
||||
|
||||
void *heapblock_alloc(size_t size)
|
||||
{
|
||||
return heapblock_alloc_aligned(size, 64);
|
||||
}
|
||||
|
||||
void *heapblock_alloc_aligned(size_t size, size_t align)
|
||||
{
|
||||
assert((align & (align - 1)) == 0);
|
||||
|
||||
uintptr_t block = (((uintptr_t)heap_base) + align - 1) & ~(align - 1);
|
||||
heap_base = (void *)(block + size);
|
||||
|
||||
return (void *)block;
|
||||
}
|
13
src/heapblock.h
Normal file
13
src/heapblock.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef HEAPBLOCK_H
|
||||
#define HEAPBLOCK_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void heapblock_init(void);
|
||||
|
||||
void *heapblock_alloc(size_t size);
|
||||
void *heapblock_alloc_aligned(size_t size, size_t align);
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "adt.h"
|
||||
#include "fb.h"
|
||||
#include "heapblock.h"
|
||||
#include "memory.h"
|
||||
#include "smp.h"
|
||||
#include "string.h"
|
||||
|
@ -45,7 +46,9 @@ void m1n1_main(void)
|
|||
printf("Licensed under the MIT license\n\n");
|
||||
|
||||
printf("Running in EL%d\n\n", mrs(CurrentEL) >> 2);
|
||||
|
||||
mmu_init();
|
||||
heapblock_init();
|
||||
|
||||
#ifdef SHOW_LOGO
|
||||
fb_init();
|
||||
|
|
14
src/malloc.h
Normal file
14
src/malloc.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef MALLOC_H
|
||||
#define MALLOC_H
|
||||
|
||||
void *malloc(size_t);
|
||||
void free(void *);
|
||||
void *calloc(size_t, size_t);
|
||||
void *realloc(void *, size_t);
|
||||
void *realloc_in_place(void *, size_t);
|
||||
void *memalign(size_t, size_t);
|
||||
int posix_memalign(void **, size_t, size_t);
|
||||
|
||||
#endif
|
15
src/proxy.c
15
src/proxy.c
|
@ -1,4 +1,6 @@
|
|||
#include "proxy.h"
|
||||
#include "heapblock.h"
|
||||
#include "malloc.h"
|
||||
#include "memory.h"
|
||||
#include "minilzlib/minlzma.h"
|
||||
#include "smp.h"
|
||||
|
@ -210,6 +212,19 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
|||
reply->retval = smp_wait(request->args[0]);
|
||||
break;
|
||||
|
||||
case P_HEAPBLOCK_ALLOC:
|
||||
reply->retval = (u64)heapblock_alloc(request->args[0]);
|
||||
break;
|
||||
case P_MALLOC:
|
||||
reply->retval = (u64)malloc(request->args[0]);
|
||||
break;
|
||||
case P_MEMALIGN:
|
||||
reply->retval = (u64)memalign(request->args[0], request->args[1]);
|
||||
break;
|
||||
case P_FREE:
|
||||
free((void *)request->args[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
reply->status = S_BADCMD;
|
||||
break;
|
||||
|
|
|
@ -62,6 +62,11 @@ typedef enum {
|
|||
P_SMP_CALL,
|
||||
P_SMP_CALL_SYNC,
|
||||
|
||||
P_HEAPBLOCK_ALLOC = 0x600, // Heap and memory management ops
|
||||
P_MALLOC,
|
||||
P_MEMALIGN,
|
||||
P_FREE,
|
||||
|
||||
} ProxyOp;
|
||||
|
||||
#define S_OK 0
|
||||
|
|
|
@ -231,6 +231,8 @@ static inline u8 mask8(u64 addr, u8 clear, u8 set)
|
|||
#define dc_civac(p) cacheop("dc civac", p)
|
||||
|
||||
extern char _base[0];
|
||||
extern char _payload_start[];
|
||||
extern char _payload_end[];
|
||||
|
||||
/*
|
||||
* These functions are guaranteed to copy by reading from src and writing to dst
|
||||
|
|
Loading…
Reference in a new issue