added an untested pmm for every machine except for PC

This commit is contained in:
Morten Delenk 2017-07-20 15:37:45 +01:00
parent d0736af522
commit 8f9423b5cd
20 changed files with 384 additions and 30 deletions

2
.gitignore vendored
View file

@ -16,3 +16,5 @@ latex/
int.s
regs.h
out/
*.mmap
*.mh

78
buildtools/mmapcomp.py Executable file
View file

@ -0,0 +1,78 @@
#!/usr/bin/env python3
import sys,os
sf = sys.argv[1]
tf = os.path.splitext(sf)[0] + ".mmap"
hf = os.path.splitext(sf)[0] + ".mh"
with open(sf) as f:
code = [ x[:-1] for x in f.readlines()]
obj = []
endian='little'
bits=32
for line in code:
data = b''
a = line.split(' ')
if a[0] == "DEVICETYPE":
data+=b'\x00'
data+=b'\x01'
devicetypes={"PC":b'\x00', "CONSOLE":b'\x01', "EMBEDDED":b'\x02'}
data+=devicetypes[a[1]]
elif a[0] == "DEVICENAME":
data+=b'\x01'
data+=len(a[1]).to_bytes(1,'little')
data+=a[1].encode("UTF-8")
elif a[0] == "CPUARCH":
data+=b'\x02'
data+=b'\x01'
archs = {"X86":b'\x00', "X86_64":b'\x01', "ARM":b'\x02'}
data+=archs[a[1]]
elif a[0] == "ENDIAN":
data+=b'\x03'
data+=b'\x01'
if a[1] == "BIG":
data+=b'\x00'
endian='big'
else:
data+=b'\x01'
endian="little"
elif a[0] == "BITS":
data+=b'\x04'
data+=b'\x01'
if a[1] == "32":
data+=b'\x20'
bits=32
else:
data+=b'\x40'
bits=64
elif a[0] == "REGION":
data+=b'\x05'
data+=(bits//4+1).to_bytes(1,endian)
data+=int(a[1],16).to_bytes(bits//8,endian)
data+=int(a[2],16).to_bytes(bits//8,endian)
perms={
"NONE": 0,
"X": 1,
"W": 2,
"WX": 3,
"R": 4,
"RX": 5,
"RW": 6,
"RWX": 7
}
data+=perms[a[3]].to_bytes(1,endian)
elif a[0] == "":
continue
else:
raise ValueError("Unknown command '"+a[0]+"'")
obj.append(data)
mmdata = b'MMAP' + bytes(4) + len(obj).to_bytes(4,'little')
for o in obj:
mmdata += o
with open(tf,"wb") as f:
f.write(mmdata)
with open(hf, "w") as f:
f.write("#pragma once\n")
f.write("#include <stdint.h>\n")
f.write("uint8_t mmap[] = {\n")
for b in mmdata:
f.write(hex(b)+", ")
f.write("\n};\n")

95
docs/mmap.md Normal file
View file

@ -0,0 +1,95 @@
# Memory Map File Format
## .mc - Clear text Memory Map
| Identifier | Meaning |
|------------|----------------------------------------------------------|
|`DEVICETYPE`|Type of the device. One of `PC`, `CONSOLE` and `EMBEDDED` |
|`DEVICENAME`|Pascal strings containing the name of the device |
|`CPUARCH` | Architecture. Currently one of `X86`, `X86_64` and `ARM` |
|`ENDIAN` | `BIG` or `LITTLE` |
|`BITS` | `32` or `64` |
|`REGION` | A region of Memory. Arguments are `START_ADDR`, `END_ADDR`, and `PERMISSIONS` (`R`, `RW`, `RX`, `RWX`) Only memory with `RWX` permissions can be allocated. |
Example:
DEVICETYPE CONSOLE
DEVICENAME 3DS9
CPUARCH ARM
ENDIAN LITTLE
BITS 32
REGION 0x00000000 0x00008000 RWX
REGION 0x08000000 0x08100000 RWX
REGION 0x10000000 0x18000000 RW
REGION 0x18000000 0x18600000 RW
REGION 0x1FF00000 0x1FF80000 RW
REGION 0x1FF80000 0x20000000 RW
REGION 0x20000000 0x28000000 RW
## .mmap - Compiled Memory Map
### Header
The header is always little-endian
| Offset | Width | Meaning |
|--------|-------|---------|
| `0x00` | 4 | Magic number `MMAP` |
| `0x04` | 4 | Version (Currently 0) |
| `0x08` | 4 | Tag count |
### Tag format
| Offset | Width | Meaning |
|--------|-------|---------|
| `0x00` | 1 | Tag type |
| `0x01` | 1 | Tag size |
| `0x02` | 2 | Paddding |
### Supported tags
| Tag Type | Size | Name |
|-|-|-|
| `0x00` | 1 | `DEVICETYPE` |
| `0x01` | variable | `DEVICENAME` |
| `0x02` | 1 | `CPUARCH` |
| `0x03` | 1 | `ENDIAN` |
| `0x04` | 1 | `BITS` |
| `0x05` | `BITS`/4 + 1 | `REGION` |
#### `DEVICETYPE`
| Value | Meaning |
|-|-|
| `0` | `PC` |
| `1` | `CONSOLE` |
| `2` | `EMBEDDED` |
#### `CPUARCH`
| Value | Meaning |
|-|-|
| 0 | `X86` |
| 1 | `X86_64` |
| 2 | `ARM` |
#### `ENDIAN`
| Value | Meaning |
|-|-|
| 0 | `BIG` |
| 1 | `LITTLE` |
#### `BITS`
This is a 8-bit integer
#### `REGION`
| Offset | Length | Meaning |
|-|-|-|
| 0 | `BITS`/8 | Start address |
| `BITS`/8 | `BITS`/8 | End address |
| `BITS`/4 | 1 | Permissions |
Permissions:
| Value | Meaning |
|-|-|
| `0` | No permission |
| `1` | `X` |
| `2` | `W` |
| `3` | `WX`|
| `4` | `R` |
| `5` | `RX` |
| `6` | `RW` |
| `7` | `RWX` |

View file

@ -2,4 +2,6 @@ config["LOWEST_CPU"] = "arm11mpcore"
config["ENABLE_HARD"] = get_yes_no("Enable VFP ABI", True)
if not config["ENABLE_HARD"]:
config["ENABLE_THUMB"] = get_yes_no("Enable Thumb")
import sys
sys.argv=["","kernel/mmaps/3ds11.mc"]
from buildtools import mmapcomp

View file

@ -2,6 +2,7 @@
#include "../../../hw/3ds11/vectorinit/vectorinit.hpp"
#include <base.hpp>
#include <config.h>
#include "../../../mmaps/3ds11.mh"
PICAfb term;
void main();

View file

@ -1,3 +1,5 @@
config["LOWEST_CPU"] = "arm946e-s"
config["ENABLE_THUMB"] = get_yes_no("Enable Thumb", True)
import sys
sys.argv=["","kernel/mmaps/3ds9.mc"]
from buildtools import mmapcomp

View file

@ -2,6 +2,7 @@
#include "../../../hw/3ds9/vectorinit/vectorinit.hpp"
#include <base.hpp>
#include <config.h>
#include "../../../mmaps/3ds9.mh"
PICAfb term;
void main();

View file

@ -1,2 +1,4 @@
config["LOWEST_CPU"] = "cortex-a7"
import sys
sys.argv=["","kernel/mmaps/raspi2.mc"]
from buildtools import mmapcomp

View file

@ -2,6 +2,7 @@
#include "../../../hw/raspi2/vector/vector.hpp"
#include <base.hpp>
#include <config.h>
#include "../../../mmaps/raspi2.mh"
Serial term;
void main();

View file

@ -8,6 +8,6 @@ if config["ENABLE_I2C"]:
add_driver(True, "framebuffer")
add_driver(False, "picafb")
add_driver(False, "vectorinit")
add_driver(False, "pmm")
add_driver(True, "pmm")
print("Enable complete Unicode font: NO (because of the size)")
config["ENABLE_FRAMEBUFFER_UNICODE"] = False

View file

@ -2,6 +2,6 @@ config["ENABLE_EXTRA_MEMORY"] = get_yes_no("Enable 512KB of memory on n3DS", Tru
add_driver(True, "framebuffer")
add_driver(False, "picafb")
add_driver(False, "vectorinit")
add_driver(False, "pmm")
add_driver(True, "pmm")
print("Enable complete Unicode font: NO (because of the size)")
config["ENABLE_FRAMEBUFFER_UNICODE"] = False

134
kernel/hw/pmm/pmm.cpp Normal file
View file

@ -0,0 +1,134 @@
#include "pmm.hpp"
#include <base.hpp>
enum class DEVICETYPE: uint8_t {
PC,
CONSOLE,
EMBEDDED
};
enum class CPUARCH: uint8_t {
X86,
X86_64,
ARM
};
enum class ENDIAN: uint8_t {
BIG,
LITTLE
};
enum class PERM: uint8_t {
NONE,
X,
W,
WX,
R,
RX,
RW,
RWX
};
struct MMAP {
char magic[4];
uint32_t version;
uint32_t length;
}__attribute__((packed));
union MMAPTag {
struct {
uint8_t id;
uint8_t size;
}__attribute__((packed));
struct {
uint8_t id;
uint8_t size;
DEVICETYPE value;
}__attribute__((packed)) DEVICETYPE;
struct {
uint8_t id;
uint8_t size;
char value[1];
}__attribute__((packed)) DEVICENAME;
struct {
uint8_t id;
uint8_t size;
CPUARCH value;
}__attribute__((packed)) CPUARCH;
struct {
uint8_t id;
uint8_t size;
ENDIAN endian;
}__attribute__((packed)) ENDIAN;
struct {
uint8_t id;
uint8_t size;
uint8_t value;
}__attribute__((packed)) BITS;
struct {
uint8_t id;
uint8_t size;
phys_t start;
phys_t end;
PERM permission;
}__attribute__((packed)) REGION;
};
extern uint8_t mmap;
PMM_MMAP::PMM_MMAP(): PMM(0x1000) {
MMAP &header = *((MMAP*)&mmap);
if((header.magic[0] != 'M')||(header.magic[1] != 'M')||(header.magic[2] != 'A')||(header.magic[3] != 'P'))
for(;;); //This is not a mmap
#ifdef __BIG_ENDIAN__
header.length = __builtin_bswap32(header.length);
#endif
uint8_t *off=(uint8_t*)(&header+1);
for(uint32_t i=0;i<header.length;i++) {
MMAPTag &tag = *((MMAPTag*)off);
off+=tag.size;
switch(tag.id) {
case 0:
case 1:
case 5:
break; //Ignored for now
case 2: //CPUARCH
if(tag.CPUARCH.value !=
#ifdef __i386__
CPUARCH::X86
#else
#ifdef __x86_64__
CPUARCH::X86_64
#else
CPUARCH::ARM
#endif
#endif
)
for(;;);
break;
case 3:
hostEndian = tag.ENDIAN.endian ==
#ifdef __BIG_ENDIAN__
ENDIAN::BIG
#else
ENDIAN::LITTLE
#endif
;
break;
case 4:
bits = tag.BITS.value;
break;
default:
for(;;);
}
}
}
PMM_MMAP::~PMM_MMAP() {}
auto PMM_MMAP::isFree(phys_t addr) -> bool {
MMAP &header = *((MMAP*)&mmap);
uint8_t *off=(uint8_t*)(&header+1);
for(uint32_t i=0;i<header.length;i++) {
MMAPTag &tag = *((MMAPTag*)off);
off+=tag.size;
if(tag.id != 5)
continue;
if((tag.REGION.start > addr) || (tag.REGION.end < addr))
continue;
if(tag.REGION.permission == PERM::RWX)
return PMM::isFree(addr);
}
return false;
}

11
kernel/hw/pmm/pmm.hpp Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include <pmm.hpp>
class PMM_MMAP: public PMM {
protected:
uint8_t bits;
bool hostEndian;
virtual auto isFree(phys_t addr) -> bool;
public:
PMM_MMAP();
virtual ~PMM_MMAP();
};

View file

@ -1,3 +1,4 @@
add_driver(False, "uart")
add_driver(False, "serial")
add_driver(False, "vector")
add_driver(True, "pmm")

11
kernel/mmaps/3ds11.mc Normal file
View file

@ -0,0 +1,11 @@
DEVICETYPE CONSOLE
DEVICENAME 3DS11
CPUARCH ARM
ENDIAN LITTLE
BITS 32
REGION 0x00000000 0x00010000 RX
REGION 0x10000000 0x18000000 RW
REGION 0x18000000 0x18600000 RW
REGION 0x1FF00000 0x1FF80000 RW
REGION 0x1FF80000 0x20000000 RW
REGION 0x20000000 0x28000000 RWX

14
kernel/mmaps/3ds9.mc Normal file
View file

@ -0,0 +1,14 @@
DEVICETYPE CONSOLE
DEVICENAME 3DS9
CPUARCH ARM
ENDIAN LITTLE
BITS 32
REGION 0x00000000 0x00008000 RW
REGION 0x08000000 0x08100000 RWX
REGION 0x10000000 0x18000000 RW
REGION 0x18000000 0x18600000 RW
REGION 0x1FF00000 0x1FF80000 RW
REGION 0x1FF80000 0x20000000 RW
REGION 0x20000000 0x28000000 RW
REGION 0xFFF00000 0xFFF04000 RW
REGION 0xFFFF0000 0x00000000 RX

6
kernel/mmaps/raspi2.mc Normal file
View file

@ -0,0 +1,6 @@
DEVICETYPE CONSOLE
DEVICENAME RASPI2
CPUARCH ARM
ENDIAN LITTLE
BITS 32
REGION 0x00000000 0x40000000 RWX

View file

@ -11,3 +11,11 @@ void setMainTTY(TTY *obj);
* Halts the kernel due to a unresolvable error
*/
extern "C" void panic(const char* s);
#if !defined(__LITTLE_ENDIAN__) || !defined(__BIG_ENDIAN__)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define __LITTLE_ENDIAN__
#else
#define __BIG_ENDIAN__
#endif
#endif

View file

@ -1,4 +1,6 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef uintptr_t phys_t; ///< Type used for physical addresses
/**
* A single entry in the PMM list
@ -7,13 +9,6 @@ struct PMM_ent {
PMM_ent* next; ///< Next element in the list
phys_t val; ///< This for not having to cast in the code.
};
/**
* Structure for a memory map
*/
struct mmap_ent {
phys_t start;
phys_t end;
}
/**
* Physical memory manager. It stores the free memory in a linked list
*/
@ -23,12 +18,12 @@ class PMM {
virtual auto isFree(phys_t addr) -> bool; ///< Returns true if the provided page is free to use
phys_t page_size; ///< Contains the size of a single memory page, in bytes
public:
PMM(phys_t page_size, mmap_ent *entries, int length);
PMM(phys_t page_size);
virtual ~PMM();
virtual auto operator<<(phys_t page) -> PMM &; ///< Frees a page. O(1)
virtual auto operator>>(phys_t &page) -> PMM &; ///< Allocates a page. O(1)
virtual auto operator,(size_t no_pages) -> phys_t; ///< Allocates multiple pages. O(n²)
virtual auto operator(phys_t pages,size_t no_pages) -> void; ///< Deallocates multiple pages. O(n)
virtual auto operator()(phys_t pages,size_t no_pages) -> void; ///< Deallocates multiple pages. O(n)
virtual auto operator&&(phys_t page) -> bool; //Returns true if this page is free. O(n).
};
/**
@ -37,4 +32,3 @@ class PMM {
#define in and
auto operator&&(phys_t a, PMM mm) -> bool; ///< Returns true when page is free. Used for syntax `page in pmm`
auto operator&&(phys_t a, PMM *mm) -> bool; ///< Returns true when page is free. Present in case that mm is a pointer.

View file

@ -11,22 +11,16 @@ auto PMM::isFree(phys_t addr) -> bool {
return false;
return true;
}
PMM::PMM(phys_t page_size, mmap_ent *entries, int length): page_size(page_size), head(nullptr) {
for(int i=0;i< length; i++) {
for(phys_t j=entries[i].start;j<entries[i].end;j+=page_size) {
if(isFree(j))
*this << j;
}
}
PMM::PMM(phys_t page_size): page_size(page_size), head(nullptr) {
}
PMM::~PMM() {}
auto PMM::operator<<(phys_t page) -> PMM & {
*this(page,1);
(*this)(page,1);
return *this;
}
auto PMM::operator>>(phys_t &page) -> PMM & {
page = *this, 1;
page = (*this, 1);
return *this;
}
@ -62,7 +56,7 @@ auto PMM::operator,(size_t no_pages) -> phys_t {
}
panic("Not enough continuous free memory is available.");
}
auto PMM::operator(phys_t pages, size_t no_pages) -> void {
auto PMM::operator()(phys_t pages, size_t no_pages) -> void {
for(size_t i=0; i<no_pages; i++, pages+=page_size) {
PMM_ent *curr=(PMM_ent *)pages;
curr->next=head;
@ -70,10 +64,10 @@ auto PMM::operator(phys_t pages, size_t no_pages) -> void {
head=curr;
}
}
virtual auto operator&&(phys_t page) -> bool {
auto PMM::operator&&(phys_t page) -> bool {
PMM_ent *curr = head;
while(curr) {
if(curr->value==page)
if(curr->val==page)
return true;
curr=curr->next;
}
@ -82,6 +76,3 @@ virtual auto operator&&(phys_t page) -> bool {
auto operator&&(phys_t a, PMM mm) -> bool {
return mm && a;
}
auto operator&&(phys_t a, PMM *mm) -> bool {
return a in *mm;
}