Skip to content

Commit b8e8e27

Browse files
committed
Basic boot skeleton.
Can be booted by the Neotron 32 BIOS. I do need to think of a nicer way of handling systems with different amounts of memory, and also to ensure global variables are initialised correctly.
1 parent 0de31fb commit b8e8e27

File tree

9 files changed

+949
-0
lines changed

9 files changed

+949
-0
lines changed

.cargo/config

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[target.thumbv7em-none-eabihf]
2+
runner = 'arm-none-eabi-gdb --command=gdb.cfg -w'
3+
rustflags = [
4+
"-C", "link-arg=-Tneotron-os-26k.ld",
5+
]
6+
7+
[build]
8+
target = "thumbv7em-none-eabihf"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
**/*.rs.bk
3+
Cargo.lock

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "common"]
2+
path = common
3+
url = ../Neotron-Common-BIOS.git

Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "neotron_os"
3+
version = "0.1.0"
4+
authors = ["Jonathan 'theJPster' Pallant <[email protected]>"]
5+
edition = "2018"
6+
description = "The Neotron Operating System"
7+
license = "GPL-3.0-or-later"
8+
readme = "README.md"
9+
repository = "https://github.com/neotron-compute/Neotron-OS"
10+
11+
[[bin]]
12+
name = "neotron_os"
13+
test = false
14+
bench = false
15+
16+
[profile.release]
17+
lto = true
18+
debug = true
19+
codegen-units = 1
20+
opt-level = "s"
21+
22+
[dependencies.neotron_common_bios]
23+
path = "./common"

LICENSE.md

Lines changed: 675 additions & 0 deletions
Large diffs are not rendered by default.

common

Submodule common added at 10e6ce2

gdb.cfg

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
target extended-remote :3333
2+
3+
# print demangled symbols by default
4+
set print asm-demangle on
5+
6+
monitor arm semihosting enable
7+
8+
# # send captured ITM to the file itm.fifo
9+
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
10+
# # 8000000 must match the core clock frequency
11+
# monitor tpiu config internal itm.fifo uart off 8000000
12+
13+
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
14+
# # 2000000 is the frequency of the SWO pin
15+
# monitor tpiu config external uart off 8000000 2000000
16+
17+
# # enable ITM port 0
18+
# monitor itm port 0 on
19+
20+
load
21+
step
22+
continue
23+
24+

neotron-os-26k.ld

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/* # Developer notes
2+
3+
- Symbols that start with a double underscore (__) are considered "private"
4+
5+
- Symbols that start with a single underscore (_) are considered "semi-public"; they can be
6+
overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" {
7+
static mut __sbss }`).
8+
9+
- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a
10+
symbol if not dropped if it appears in or near the front of the linker arguments and "it's not
11+
needed" by any of the preceding objects (linker arguments)
12+
13+
- `PROVIDE` is used to provide default values that can be overridden by a user linker script
14+
15+
- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and*
16+
the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization
17+
routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see
18+
"Address (..) is out of bounds" in the disassembly produced by `objdump`.
19+
*/
20+
21+
/* Provides information about the memory layout of the device */
22+
MEMORY
23+
{
24+
/* The OS gets the top 128 KiB of Flash, leaving the first 128 KiB for the BIOS */
25+
FLASH (rx) : ORIGIN = 0x00020000, LENGTH = 128K
26+
/* The BIOS gets the top 6 KiB of SRAM (including the Stack), leaving 26 KiB for the OS (at 0x2000_0000 to 0x2000_67FF) */
27+
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 26K
28+
}
29+
30+
/* # Entry point = what the BIOS calls to start the OS */
31+
ENTRY(entry_point);
32+
EXTERN(__RESET_VECTOR);
33+
34+
/* # Sections */
35+
SECTIONS
36+
{
37+
38+
/* ## Sections in FLASH */
39+
.entry_point ORIGIN(FLASH) :
40+
{
41+
KEEP(*(.entry_point))
42+
} > FLASH
43+
44+
PROVIDE(_stext = ADDR(.entry_point) + SIZEOF(.entry_point));
45+
46+
/* ### .text */
47+
.text _stext :
48+
{
49+
*(.text .text.*);
50+
*(.HardFaultTrampoline);
51+
*(.HardFault.*);
52+
} > FLASH
53+
54+
/* ### .rodata */
55+
.rodata : ALIGN(4)
56+
{
57+
*(.rodata .rodata.*);
58+
59+
/* 4-byte align the end (VMA) of this section.
60+
This is required by LLD to ensure the LMA of the following .data
61+
section will have the correct alignment. */
62+
. = ALIGN(4);
63+
} > FLASH
64+
65+
/* ## Sections in RAM */
66+
/* ### .data */
67+
.data : ALIGN(4)
68+
{
69+
. = ALIGN(4);
70+
__sdata = .;
71+
*(.data .data.*);
72+
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
73+
__edata = .;
74+
} > RAM AT > FLASH
75+
76+
/* LMA of .data */
77+
__sidata = LOADADDR(.data);
78+
79+
/* ### .bss */
80+
.bss : ALIGN(4)
81+
{
82+
. = ALIGN(4);
83+
__sbss = .;
84+
*(.bss .bss.*);
85+
. = ALIGN(4); /* 4-byte align the end (VMA) of this section */
86+
__ebss = .;
87+
} > RAM
88+
89+
/* ### .uninit */
90+
.uninit (NOLOAD) : ALIGN(4)
91+
{
92+
. = ALIGN(4);
93+
*(.uninit .uninit.*);
94+
. = ALIGN(4);
95+
} > RAM
96+
97+
/* Place the heap right after `.uninit` */
98+
. = ALIGN(4);
99+
__sheap = .;
100+
101+
/* ## .got */
102+
/* Dynamic relocations are unsupported. This section is only used to detect relocatable code in
103+
the input files and raise an error if relocatable code is found */
104+
.got (NOLOAD) :
105+
{
106+
KEEP(*(.got .got.*));
107+
}
108+
109+
/* ## Discarded sections */
110+
/DISCARD/ :
111+
{
112+
/* Unused exception related info that only wastes space */
113+
*(.ARM.exidx);
114+
*(.ARM.exidx.*);
115+
*(.ARM.extab.*);
116+
}
117+
}
118+
119+
/* Do not exceed this mark in the error messages below | */
120+
/* # Alignment checks */
121+
ASSERT(ORIGIN(FLASH) % 4 == 0, "
122+
ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned");
123+
124+
ASSERT(ORIGIN(RAM) % 4 == 0, "
125+
ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned");
126+
127+
ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, "
128+
BUG(cortex-m-rt): .data is not 4-byte aligned");
129+
130+
ASSERT(__sidata % 4 == 0, "
131+
BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned");
132+
133+
ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, "
134+
BUG(cortex-m-rt): .bss is not 4-byte aligned");
135+
136+
ASSERT(__sheap % 4 == 0, "
137+
BUG(cortex-m-rt): start of .heap is not 4-byte aligned");
138+
139+
/* # Position checks */
140+
141+
/* ## .text */
142+
ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), "
143+
ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory.
144+
Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'");
145+
146+
/* # Other checks */
147+
ASSERT(SIZEOF(.got) == 0, "
148+
ERROR(cortex-m-rt): .got section detected in the input object files
149+
Dynamic relocations are not supported. If you are linking to C code compiled using
150+
the 'cc' crate then modify your build script to compile the C code _without_
151+
the -fPIC flag. See the documentation of the `cc::Build.pic` method for details.");
152+
/* Do not exceed this mark in the error messages above | */

src/main.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//! # The Neotron Operating System
2+
//!
3+
//! This OS is intended to be loaded by a Neotron BIOS.
4+
#![no_std]
5+
#![no_main]
6+
7+
use core::fmt::Write;
8+
use neotron_common_bios as common;
9+
10+
#[link_section = ".entry_point"]
11+
#[no_mangle]
12+
#[used]
13+
pub static ENTRY_POINT: extern "C" fn(&'static common::Api) -> ! = entry_point;
14+
15+
static mut API: Option<&'static common::Api> = None;
16+
17+
struct SerialConsole;
18+
19+
impl core::fmt::Write for SerialConsole {
20+
fn write_str(&mut self, data: &str) -> core::fmt::Result {
21+
if let Some(api) = unsafe { API } {
22+
let _res = (api.serial_write)(
23+
0,
24+
common::ApiByteSlice::new(data.as_bytes()),
25+
common::Option::None,
26+
);
27+
}
28+
Ok(())
29+
}
30+
}
31+
32+
#[no_mangle]
33+
extern "C" fn entry_point(api: &'static common::Api) -> ! {
34+
unsafe {
35+
API = Some(api);
36+
}
37+
writeln!(SerialConsole, "Neotron OS.").unwrap();
38+
writeln!(SerialConsole, "BIOS Version: {}", (api.bios_version_get)()).unwrap();
39+
writeln!(
40+
SerialConsole,
41+
"BIOS API Version: {}",
42+
(api.api_version_get)()
43+
)
44+
.unwrap();
45+
loop {
46+
for _ in 0..80_000_000 {
47+
let _ = (api.api_version_get)();
48+
}
49+
writeln!(SerialConsole, "tick...").unwrap();
50+
}
51+
}
52+
53+
#[inline(never)]
54+
#[panic_handler]
55+
fn panic(_info: &core::panic::PanicInfo) -> ! {
56+
use core::sync::atomic::{self, Ordering};
57+
loop {
58+
atomic::compiler_fence(Ordering::SeqCst);
59+
}
60+
}

0 commit comments

Comments
 (0)