From eb61470e2267c1917b17120fbd6ebd121467989c Mon Sep 17 00:00:00 2001 From: Chen Wang Date: Tue, 4 Jun 2024 21:15:33 +0800 Subject: [PATCH] Improve memory/page init Align heap start and caculate number of reserved pages according to the length of ram available. See https://gitee.com/unicornx/riscv-operating-system-mooc/issues/I9LNCF. Signed-off-by: Chen Wang --- code/os/00-bootstrap/Makefile | 2 +- code/os/01-helloRVOS/Makefile | 2 +- code/os/02-memanagement/os.ld | 4 ++- code/os/02-memanagement/page.c | 40 +++++++++++++++++++++++++---- code/os/02-memanagement/platform.h | 3 +++ code/os/03-contextswitch/os.ld | 4 ++- code/os/03-contextswitch/page.c | 40 +++++++++++++++++++++++++---- code/os/03-contextswitch/platform.h | 3 +++ code/os/04-multitask/os.ld | 4 ++- code/os/04-multitask/page.c | 40 +++++++++++++++++++++++++---- code/os/04-multitask/platform.h | 3 +++ code/os/05-traps/os.ld | 4 ++- code/os/05-traps/page.c | 40 +++++++++++++++++++++++++---- code/os/05-traps/platform.h | 3 +++ code/os/06-interrupts/os.ld | 4 ++- code/os/06-interrupts/page.c | 40 +++++++++++++++++++++++++---- code/os/06-interrupts/platform.h | 3 +++ code/os/07-hwtimer/os.ld | 4 ++- code/os/07-hwtimer/page.c | 40 +++++++++++++++++++++++++---- code/os/07-hwtimer/platform.h | 3 +++ code/os/08-preemptive/os.ld | 4 ++- code/os/08-preemptive/page.c | 40 +++++++++++++++++++++++++---- code/os/08-preemptive/platform.h | 3 +++ code/os/09-lock/os.ld | 4 ++- code/os/09-lock/page.c | 40 +++++++++++++++++++++++++---- code/os/09-lock/platform.h | 3 +++ code/os/10-swtimer/os.ld | 4 ++- code/os/10-swtimer/page.c | 40 +++++++++++++++++++++++++---- code/os/10-swtimer/platform.h | 3 +++ code/os/11-syscall/os.ld | 4 ++- code/os/11-syscall/page.c | 40 +++++++++++++++++++++++++---- code/os/11-syscall/platform.h | 3 +++ code/os/common.mk | 18 +++++++++++-- 33 files changed, 428 insertions(+), 64 deletions(-) diff --git a/code/os/00-bootstrap/Makefile b/code/os/00-bootstrap/Makefile index 3ef9ace..4e393c1 100644 --- a/code/os/00-bootstrap/Makefile +++ b/code/os/00-bootstrap/Makefile @@ -1,4 +1,4 @@ -LDFLAGS = -Ttext=0x80000000 +USE_LINKER_SCRIPT = false SRCS_ASM = \ start.S \ diff --git a/code/os/01-helloRVOS/Makefile b/code/os/01-helloRVOS/Makefile index a98b28c..fcbac33 100644 --- a/code/os/01-helloRVOS/Makefile +++ b/code/os/01-helloRVOS/Makefile @@ -1,4 +1,4 @@ -LDFLAGS = -Ttext=0x80000000 +USE_LINKER_SCRIPT = false SRCS_ASM = \ start.S \ diff --git a/code/os/02-memanagement/os.ld b/code/os/02-memanagement/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/02-memanagement/os.ld +++ b/code/os/02-memanagement/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/02-memanagement/page.c b/code/os/02-memanagement/page.c index 72f63ed..59eca16 100644 --- a/code/os/02-memanagement/page.c +++ b/code/os/02-memanagement/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/02-memanagement/platform.h b/code/os/02-memanagement/platform.h index ea100ba..7ff0074 100644 --- a/code/os/02-memanagement/platform.h +++ b/code/os/02-memanagement/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/03-contextswitch/os.ld b/code/os/03-contextswitch/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/03-contextswitch/os.ld +++ b/code/os/03-contextswitch/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/03-contextswitch/page.c b/code/os/03-contextswitch/page.c index 72f63ed..59eca16 100644 --- a/code/os/03-contextswitch/page.c +++ b/code/os/03-contextswitch/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/03-contextswitch/platform.h b/code/os/03-contextswitch/platform.h index ea100ba..7ff0074 100644 --- a/code/os/03-contextswitch/platform.h +++ b/code/os/03-contextswitch/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/04-multitask/os.ld b/code/os/04-multitask/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/04-multitask/os.ld +++ b/code/os/04-multitask/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/04-multitask/page.c b/code/os/04-multitask/page.c index 72f63ed..59eca16 100644 --- a/code/os/04-multitask/page.c +++ b/code/os/04-multitask/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/04-multitask/platform.h b/code/os/04-multitask/platform.h index ea100ba..7ff0074 100644 --- a/code/os/04-multitask/platform.h +++ b/code/os/04-multitask/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/05-traps/os.ld b/code/os/05-traps/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/05-traps/os.ld +++ b/code/os/05-traps/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/05-traps/page.c b/code/os/05-traps/page.c index 72f63ed..59eca16 100644 --- a/code/os/05-traps/page.c +++ b/code/os/05-traps/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/05-traps/platform.h b/code/os/05-traps/platform.h index ea100ba..7ff0074 100644 --- a/code/os/05-traps/platform.h +++ b/code/os/05-traps/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/06-interrupts/os.ld b/code/os/06-interrupts/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/06-interrupts/os.ld +++ b/code/os/06-interrupts/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/06-interrupts/page.c b/code/os/06-interrupts/page.c index 72f63ed..59eca16 100644 --- a/code/os/06-interrupts/page.c +++ b/code/os/06-interrupts/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/06-interrupts/platform.h b/code/os/06-interrupts/platform.h index e757dc5..e706ae7 100644 --- a/code/os/06-interrupts/platform.h +++ b/code/os/06-interrupts/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/07-hwtimer/os.ld b/code/os/07-hwtimer/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/07-hwtimer/os.ld +++ b/code/os/07-hwtimer/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/07-hwtimer/page.c b/code/os/07-hwtimer/page.c index 72f63ed..59eca16 100644 --- a/code/os/07-hwtimer/page.c +++ b/code/os/07-hwtimer/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/07-hwtimer/platform.h b/code/os/07-hwtimer/platform.h index 941ecc2..2694308 100644 --- a/code/os/07-hwtimer/platform.h +++ b/code/os/07-hwtimer/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/08-preemptive/os.ld b/code/os/08-preemptive/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/08-preemptive/os.ld +++ b/code/os/08-preemptive/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/08-preemptive/page.c b/code/os/08-preemptive/page.c index 72f63ed..59eca16 100644 --- a/code/os/08-preemptive/page.c +++ b/code/os/08-preemptive/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/08-preemptive/platform.h b/code/os/08-preemptive/platform.h index 941ecc2..2694308 100644 --- a/code/os/08-preemptive/platform.h +++ b/code/os/08-preemptive/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/09-lock/os.ld b/code/os/09-lock/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/09-lock/os.ld +++ b/code/os/09-lock/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/09-lock/page.c b/code/os/09-lock/page.c index 72f63ed..59eca16 100644 --- a/code/os/09-lock/page.c +++ b/code/os/09-lock/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/09-lock/platform.h b/code/os/09-lock/platform.h index 941ecc2..2694308 100644 --- a/code/os/09-lock/platform.h +++ b/code/os/09-lock/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/10-swtimer/os.ld b/code/os/10-swtimer/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/10-swtimer/os.ld +++ b/code/os/10-swtimer/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/10-swtimer/page.c b/code/os/10-swtimer/page.c index 72f63ed..59eca16 100644 --- a/code/os/10-swtimer/page.c +++ b/code/os/10-swtimer/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/10-swtimer/platform.h b/code/os/10-swtimer/platform.h index 941ecc2..2694308 100644 --- a/code/os/10-swtimer/platform.h +++ b/code/os/10-swtimer/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/11-syscall/os.ld b/code/os/11-syscall/os.ld index dc0eb1a..9ec5eb4 100644 --- a/code/os/11-syscall/os.ld +++ b/code/os/11-syscall/os.ld @@ -3,6 +3,8 @@ * Linker script for outputting to RVOS */ +#include "platform.h" + /* * https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html * OUTPUT_ARCH command specifies a particular output machine architecture. @@ -47,7 +49,7 @@ ENTRY( _start ) */ MEMORY { - ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 128M + ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM } /* diff --git a/code/os/11-syscall/page.c b/code/os/11-syscall/page.c index 72f63ed..59eca16 100644 --- a/code/os/11-syscall/page.c +++ b/code/os/11-syscall/page.c @@ -76,22 +76,52 @@ static inline ptr_t _align_page(ptr_t address) return (address + order) & (~order); } +/* + * ______________________________HEAP_SIZE_______________________________ + * / ___num_reserved_pages___ ______________num_pages______________ \ + * / / \ / \ \ + * |---|<--Page-->|<--Page-->|...|<--Page-->|<--Page-->|......|<--Page-->|---| + * A A A A A + * | | | | | + * | | | | _memory_end + * | | | | + * | _heap_start_aligned _alloc_start _alloc_end + * HEAP_START(BSS_END) + * + * Note: _alloc_end may equal to _memory_end. + */ void page_init() { + ptr_t _heap_start_aligned = _align_page(HEAP_START); + /* - * We reserved 8 Page (8 x 4096) to hold the Page structures. - * It should be enough to manage at most 128 MB (8 x 4096 x 4096) + * We reserved some Pages to hold the Page structures. + * The number of reserved pages depends on the LENGTH_RAM. + * For simplicity, the space we reserve here is just an approximation, + * assuming that it can accommodate the maximum LENGTH_RAM. + * We assume LENGTH_RAM should not be too small, ideally no less + * than 16M (i.e. PAGE_SIZE * PAGE_SIZE). */ - _num_pages = (HEAP_SIZE / PAGE_SIZE) - 8; - printf("HEAP_START = %p, HEAP_SIZE = 0x%lx, num of pages = %d\n", HEAP_START, HEAP_SIZE, _num_pages); + uint32_t num_reserved_pages = LENGTH_RAM / (PAGE_SIZE * PAGE_SIZE); + + _num_pages = (HEAP_SIZE - (_heap_start_aligned - HEAP_START))/ PAGE_SIZE - num_reserved_pages; + printf("HEAP_START = %p(aligned to %p), HEAP_SIZE = 0x%lx,\n" + "num of reserved pages = %d, num of pages to be allocated for heap = %d\n", + HEAP_START, _heap_start_aligned, HEAP_SIZE, + num_reserved_pages, _num_pages); + /* + * We use HEAP_START, not _heap_start_aligned as begin address for + * allocating struct Page, because we have no requirement of alignment + * for position of struct Page. + */ struct Page *page = (struct Page *)HEAP_START; for (int i = 0; i < _num_pages; i++) { _clear(page); page++; } - _alloc_start = _align_page(HEAP_START + 8 * PAGE_SIZE); + _alloc_start = _heap_start_aligned + num_reserved_pages * PAGE_SIZE; _alloc_end = _alloc_start + (PAGE_SIZE * _num_pages); printf("TEXT: %p -> %p\n", TEXT_START, TEXT_END); diff --git a/code/os/11-syscall/platform.h b/code/os/11-syscall/platform.h index 941ecc2..2694308 100644 --- a/code/os/11-syscall/platform.h +++ b/code/os/11-syscall/platform.h @@ -12,6 +12,9 @@ */ #define MAXNUM_CPU 8 +/* used in os.ld */ +#define LENGTH_RAM 128*1024*1024 + /* * MemoryMap * see https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c, virt_memmap[] diff --git a/code/os/common.mk b/code/os/common.mk index 48fc8f4..11feb45 100644 --- a/code/os/common.mk +++ b/code/os/common.mk @@ -3,14 +3,12 @@ # Custom Macro Definition (Common part) - include ../defines.mk DEFS += CROSS_COMPILE = riscv64-unknown-elf- CFLAGS += -nostdlib -fno-builtin -g -Wall CFLAGS += -march=rv32g -mabi=ilp32 -LDFLAGS ?= -T os.ld QEMU = qemu-system-riscv32 QFLAGS = -nographic -smp 1 -machine virt -bios none @@ -32,6 +30,13 @@ OBJS = ${OBJS_ASM} ${OBJS_C} ELF = ${OUTPUT_PATH}/os.elf BIN = ${OUTPUT_PATH}/os.bin +USE_LINKER_SCRIPT ?= true +ifeq (${USE_LINKER_SCRIPT}, true) +LDFLAGS = -T ${OUTPUT_PATH}/os.ld.generated +else +LDFLAGS = -Ttext=0x80000000 +endif + .DEFAULT_GOAL := all all: ${OUTPUT_PATH} ${ELF} @@ -39,7 +44,16 @@ ${OUTPUT_PATH}: @${MKDIR} $@ # start.o must be the first in dependency! +# +# For USE_LINKER_SCRIPT == true, before do link, run preprocessor manually for +# linker script. +# -E specifies GCC to only run preprocessor +# -P prevents preprocessor from generating linemarkers (#line directives) +# -x c tells GCC to treat your linker script as C source file ${ELF}: ${OBJS} +ifeq (${USE_LINKER_SCRIPT}, true) + ${CC} -E -P -x c ${DEFS} ${CFLAGS} os.ld > ${OUTPUT_PATH}/os.ld.generated +endif ${CC} ${CFLAGS} ${LDFLAGS} -o ${ELF} $^ ${OBJCOPY} -O binary ${ELF} ${BIN}