diff --git a/.gitignore b/.gitignore index 05f7b11..ea18af6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ latex/ int.s regs.h out/ +*.mmap +*.mh diff --git a/buildtools/mmapcomp.py b/buildtools/mmapcomp.py new file mode 100755 index 0000000..e445d9a --- /dev/null +++ b/buildtools/mmapcomp.py @@ -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 \n") + f.write("uint8_t mmap[] = {\n") + for b in mmdata: + f.write(hex(b)+", ") + f.write("\n};\n") diff --git a/docs/mmap.md b/docs/mmap.md new file mode 100644 index 0000000..ddcddc0 --- /dev/null +++ b/docs/mmap.md @@ -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` | diff --git a/kernel/arch/arm/3ds11/config.py b/kernel/arch/arm/3ds11/config.py index 572e831..beba60e 100644 --- a/kernel/arch/arm/3ds11/config.py +++ b/kernel/arch/arm/3ds11/config.py @@ -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 diff --git a/kernel/arch/arm/3ds11/start.cpp b/kernel/arch/arm/3ds11/start.cpp index 57ef89a..fb40966 100644 --- a/kernel/arch/arm/3ds11/start.cpp +++ b/kernel/arch/arm/3ds11/start.cpp @@ -2,6 +2,7 @@ #include "../../../hw/3ds11/vectorinit/vectorinit.hpp" #include #include +#include "../../../mmaps/3ds11.mh" PICAfb term; void main(); diff --git a/kernel/arch/arm/3ds9/config.py b/kernel/arch/arm/3ds9/config.py index 2e7d23e..59e3c1d 100644 --- a/kernel/arch/arm/3ds9/config.py +++ b/kernel/arch/arm/3ds9/config.py @@ -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 diff --git a/kernel/arch/arm/3ds9/start.cpp b/kernel/arch/arm/3ds9/start.cpp index e195178..b7fbe53 100644 --- a/kernel/arch/arm/3ds9/start.cpp +++ b/kernel/arch/arm/3ds9/start.cpp @@ -2,6 +2,7 @@ #include "../../../hw/3ds9/vectorinit/vectorinit.hpp" #include #include +#include "../../../mmaps/3ds9.mh" PICAfb term; void main(); diff --git a/kernel/arch/arm/raspi2/config.py b/kernel/arch/arm/raspi2/config.py index 3c32e91..73c1649 100644 --- a/kernel/arch/arm/raspi2/config.py +++ b/kernel/arch/arm/raspi2/config.py @@ -1,2 +1,4 @@ config["LOWEST_CPU"] = "cortex-a7" - +import sys +sys.argv=["","kernel/mmaps/raspi2.mc"] +from buildtools import mmapcomp diff --git a/kernel/arch/arm/raspi2/start.cpp b/kernel/arch/arm/raspi2/start.cpp index 62e6214..2c28464 100644 --- a/kernel/arch/arm/raspi2/start.cpp +++ b/kernel/arch/arm/raspi2/start.cpp @@ -2,6 +2,7 @@ #include "../../../hw/raspi2/vector/vector.hpp" #include #include +#include "../../../mmaps/raspi2.mh" Serial term; void main(); diff --git a/kernel/hw/3ds11/config.py b/kernel/hw/3ds11/config.py index 9c7737d..8d0e857 100644 --- a/kernel/hw/3ds11/config.py +++ b/kernel/hw/3ds11/config.py @@ -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 diff --git a/kernel/hw/3ds9/config.py b/kernel/hw/3ds9/config.py index fd8cd7a..897273f 100644 --- a/kernel/hw/3ds9/config.py +++ b/kernel/hw/3ds9/config.py @@ -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 diff --git a/kernel/hw/pmm/pmm.cpp b/kernel/hw/pmm/pmm.cpp new file mode 100644 index 0000000..a7662cd --- /dev/null +++ b/kernel/hw/pmm/pmm.cpp @@ -0,0 +1,134 @@ +#include "pmm.hpp" +#include +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 bool { + MMAP &header = *((MMAP*)&mmap); + uint8_t *off=(uint8_t*)(&header+1); + for(uint32_t i=0;i addr) || (tag.REGION.end < addr)) + continue; + if(tag.REGION.permission == PERM::RWX) + return PMM::isFree(addr); + } + return false; +} diff --git a/kernel/hw/pmm/pmm.hpp b/kernel/hw/pmm/pmm.hpp new file mode 100644 index 0000000..76501c8 --- /dev/null +++ b/kernel/hw/pmm/pmm.hpp @@ -0,0 +1,11 @@ +#pragma once +#include +class PMM_MMAP: public PMM { + protected: + uint8_t bits; + bool hostEndian; + virtual auto isFree(phys_t addr) -> bool; + public: + PMM_MMAP(); + virtual ~PMM_MMAP(); +}; diff --git a/kernel/hw/raspi2/config.py b/kernel/hw/raspi2/config.py index 42559c9..fbdd773 100644 --- a/kernel/hw/raspi2/config.py +++ b/kernel/hw/raspi2/config.py @@ -1,3 +1,4 @@ add_driver(False, "uart") add_driver(False, "serial") add_driver(False, "vector") +add_driver(True, "pmm") diff --git a/kernel/mmaps/3ds11.mc b/kernel/mmaps/3ds11.mc new file mode 100644 index 0000000..ce8cc6c --- /dev/null +++ b/kernel/mmaps/3ds11.mc @@ -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 diff --git a/kernel/mmaps/3ds9.mc b/kernel/mmaps/3ds9.mc new file mode 100644 index 0000000..8f6ab97 --- /dev/null +++ b/kernel/mmaps/3ds9.mc @@ -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 diff --git a/kernel/mmaps/raspi2.mc b/kernel/mmaps/raspi2.mc new file mode 100644 index 0000000..9070b65 --- /dev/null +++ b/kernel/mmaps/raspi2.mc @@ -0,0 +1,6 @@ +DEVICETYPE CONSOLE +DEVICENAME RASPI2 +CPUARCH ARM +ENDIAN LITTLE +BITS 32 +REGION 0x00000000 0x40000000 RWX diff --git a/kernel/src/include/base.hpp b/kernel/src/include/base.hpp index 5084aec..6946216 100644 --- a/kernel/src/include/base.hpp +++ b/kernel/src/include/base.hpp @@ -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 diff --git a/kernel/src/include/pmm.hpp b/kernel/src/include/pmm.hpp index 7dc70f9..a2c58df 100644 --- a/kernel/src/include/pmm.hpp +++ b/kernel/src/include/pmm.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include 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. diff --git a/kernel/src/pmm.cpp.old b/kernel/src/pmm.cpp similarity index 77% rename from kernel/src/pmm.cpp.old rename to kernel/src/pmm.cpp index 5368c0b..976d48a 100644 --- a/kernel/src/pmm.cpp.old +++ b/kernel/src/pmm.cpp @@ -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 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; inext=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; -}