Skip to content

Commit ba9e8d6

Browse files
Working on API support.
1 parent fb844f6 commit ba9e8d6

5 files changed

Lines changed: 246 additions & 21 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ rp-pico = "0.5"
1515
# Cortex-M run-time (or start-up) code
1616
cortex-m-rt = "0.7"
1717
# The BIOS to OS API
18-
neotron-common-bios = "0.5.0"
18+
neotron-common-bios = "0.7.0"
1919
# For the RP2040 bootloader
2020
rp2040-boot2 = "0.2"
2121
# For hardware abstraction traits

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ user@host ~ $ cargo install probe-rs
6060
We use the "neotron-os-pico.ld" linker script to link it at `0x1002_0000`.
6161

6262
```console
63-
user@host ~/neotron-os $ cargo build --release
63+
user@host ~/neotron-os $ cargo build --bin=flash1002 --release --target=thumbv6m-none-eabi
6464
user@host ~/neotron-os $ arm-none-eabi-objcopy -O binary ./target/thumbv6m-none-eabi/release/flash1002 ../neotron-pico-bios/src/flash1002.bin
6565
```
6666

src/flash1002.bin

9.7 KB
Binary file not shown.

src/main.rs

Lines changed: 217 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ static API_CALLS: common::Api = common::Api {
156156
serial_get_info,
157157
serial_write,
158158
serial_read,
159-
time_get,
160-
time_set,
159+
time_clock_get,
160+
time_clock_set,
161161
configuration_get,
162162
configuration_set,
163163
video_is_valid_mode,
@@ -174,6 +174,30 @@ static API_CALLS: common::Api = common::Api {
174174
block_write,
175175
block_read,
176176
block_verify,
177+
time_ticks_get,
178+
time_ticks_per_second,
179+
video_get_palette,
180+
video_set_palette,
181+
video_set_whole_palette,
182+
i2c_bus_get_info,
183+
i2c_write_read,
184+
audio_mixer_channel_get_info,
185+
audio_mixer_channel_set_level,
186+
audio_output_set_config,
187+
audio_output_get_config,
188+
audio_output_data,
189+
audio_output_get_space,
190+
audio_input_set_config,
191+
audio_input_get_config,
192+
audio_input_data,
193+
audio_input_get_count,
194+
bus_select,
195+
bus_get_info,
196+
bus_write_read,
197+
bus_exchange,
198+
bus_interrupt_status,
199+
block_dev_eject,
200+
power_idle,
177201
};
178202

179203
extern "C" {
@@ -297,13 +321,8 @@ fn main() -> ! {
297321
sign_on();
298322

299323
// Now jump to the OS
300-
// let code: &common::OsStartFn = unsafe { ::core::mem::transmute(&_flash_os_start) };
301-
// code(&API_CALLS);
302-
303-
// OS has returned?! Just hang.
304-
loop {
305-
cortex_m::asm::wfi();
306-
}
324+
let code: &common::OsStartFn = unsafe { ::core::mem::transmute(&_flash_os_start) };
325+
code(&API_CALLS);
307326
}
308327

309328
impl Hardware {
@@ -642,20 +661,20 @@ impl Hardware {
642661
// Dump registers
643662
for reg in 0x00..=0x15 {
644663
let data = self.io_chip_read(reg);
645-
defmt::debug!("Reg 0x{:02x} => 0x{:02x}", reg, data);
646664
}
647665
}
648666

649667
/// Read the BMC firmware version string.
650668
///
651669
/// You get 32 bytes of probably UTF-8 data.
652670
fn bmc_read_firmware_version(&mut self) -> Result<[u8; 32], ()> {
653-
let req = neotron_bmc_protocol::Request::new_read(false, 0, 32);
671+
let req = neotron_bmc_protocol::Request::new_read(false, 0x01, 32);
654672
let mut buffer = [0xFF; 64];
655673
buffer[0..=3].copy_from_slice(&req.as_bytes());
656674
self.with_bus_cs(0, |spi| {
657675
spi.transfer(&mut buffer).unwrap();
658676
});
677+
defmt::info!("buffer: {=[u8]:x}", buffer);
659678
let mut result = &buffer[..];
660679
let mut latency = 0;
661680
while result.len() > 0 && result[0] == 0xFF {
@@ -694,6 +713,53 @@ impl Hardware {
694713

695714
Err(())
696715
}
716+
717+
/// Read the BMC PS/2 keyboard FIFO.
718+
///
719+
/// We ask for 8 bytes of data. We get `1` byte of 'length', then `N` bytes of valid data, and `32 - (N + 1)` bytes of padding.
720+
fn bmc_read_ps2_keyboard_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, ()> {
721+
let req = neotron_bmc_protocol::Request::new_read(false, 0x40, 8);
722+
let mut buffer = [0xFF; 42];
723+
buffer[0..=3].copy_from_slice(&req.as_bytes());
724+
self.with_bus_cs(0, |spi| {
725+
spi.transfer(&mut buffer).unwrap();
726+
});
727+
defmt::info!("buffer: {=[u8]:x}", buffer);
728+
let mut result = &buffer[..];
729+
let mut latency = 0;
730+
while result.len() > 0 && result[0] == 0xFF {
731+
latency += 1;
732+
result = &result[1..];
733+
}
734+
defmt::info!("latency: {}", latency);
735+
// 8 bytes of data requested, plus one bytes of response code and one byte of CRC
736+
if result.len() >= 10 {
737+
match neotron_bmc_protocol::Response::from_bytes(&result[0..10]) {
738+
Ok(res) => {
739+
if res.result == neotron_bmc_protocol::ResponseResult::Ok && res.data.len() == 8
740+
{
741+
defmt::info!("Got PS/2 bytes {=[u8]:x}", res.data);
742+
return Ok(0);
743+
} else {
744+
defmt::warn!(
745+
"Error getting keyboard bytes: Error from BMC {:?} {=[u8]:x}",
746+
res.result,
747+
res.data
748+
);
749+
}
750+
}
751+
Err(e) => {
752+
defmt::warn!(
753+
"Error getting BMC keyboard bytes: Decoding Error {:?} {=[u8]:x}",
754+
e,
755+
result
756+
);
757+
}
758+
}
759+
}
760+
761+
Err(())
762+
}
697763
}
698764

699765
fn sign_on() {
@@ -735,6 +801,12 @@ fn sign_on() {
735801
writeln!(&tc, "BMC Version: Error reading").unwrap();
736802
}
737803
}
804+
805+
critical_section::with(|cs| {
806+
let mut lock = HARDWARE.borrow_ref_mut(cs);
807+
let hw = lock.as_mut().unwrap();
808+
hw.delay.delay_ms(5000);
809+
});
738810
}
739811

740812
/// Reset the DMA Peripheral.
@@ -825,7 +897,7 @@ pub extern "C" fn serial_read(
825897
///
826898
/// If the BIOS does not have a battery-backed clock, or if that battery has
827899
/// failed to keep time, the system starts up assuming it is the epoch.
828-
pub extern "C" fn time_get() -> common::Time {
900+
pub extern "C" fn time_clock_get() -> common::Time {
829901
// TODO: Read from the MCP7940N
830902
common::Time { secs: 0, nsecs: 0 }
831903
}
@@ -839,7 +911,7 @@ pub extern "C" fn time_get() -> common::Time {
839911
/// time (e.g. the user has updated the current time, or if you get a GPS
840912
/// fix). The BIOS should push the time out to the battery-backed Real
841913
/// Time Clock, if it has one.
842-
pub extern "C" fn time_set(_time: common::Time) {
914+
pub extern "C" fn time_clock_set(_time: common::Time) {
843915
// TODO: Update the MCP7940N RTC
844916
}
845917

@@ -950,24 +1022,28 @@ pub extern "C" fn video_mode_needs_vram(_mode: common::video::Mode) -> bool {
9501022
/// (other than Region 0), so faster memory should be listed first.
9511023
///
9521024
/// If the region number given is invalid, the function returns `(null, 0)`.
953-
pub extern "C" fn memory_get_region(region: u8) -> common::Result<common::MemoryRegion> {
1025+
pub extern "C" fn memory_get_region(region: u8) -> common::Option<common::MemoryRegion> {
9541026
match region {
9551027
0 => {
9561028
// Application Region
957-
common::Result::Ok(MemoryRegion {
1029+
common::Option::Some(MemoryRegion {
9581030
start: unsafe { &mut _ram_os_start as *mut u32 } as *mut u8,
9591031
length: unsafe { &mut _ram_os_len as *const u32 } as usize,
9601032
kind: common::MemoryKind::Ram,
9611033
})
9621034
}
963-
_ => common::Result::Err(common::Error::InvalidDevice),
1035+
_ => common::Option::None,
9641036
}
9651037
}
9661038

9671039
/// Get the next available HID event, if any.
9681040
///
9691041
/// This function doesn't block. It will return `Ok(None)` if there is no event ready.
9701042
pub extern "C" fn hid_get_event() -> common::Result<common::Option<common::hid::HidEvent>> {
1043+
// todo: call bmc_read_ps2_keyboard_fifo()
1044+
// todo: decode the PS/2 bytes we receive into HidEvents
1045+
// todo: cache all the bytes that don't make up a full HID event
1046+
9711047
// TODO: Support some HID events
9721048
common::Result::Ok(common::Option::None)
9731049
}
@@ -1013,6 +1089,109 @@ pub extern "C" fn video_wait_for_line(line: u16) {
10131089
}
10141090
}
10151091

1092+
/// Read the RGB palette. Currently we only have two colours and you can't
1093+
/// change them.
1094+
extern "C" fn video_get_palette(index: u8) -> common::Option<common::video::RGBColour> {
1095+
match index {
1096+
0 => common::Option::Some(vga::colours::BLUE.into()),
1097+
1 => common::Option::Some(vga::colours::YELLOW.into()),
1098+
_ => common::Option::None,
1099+
}
1100+
}
1101+
1102+
/// Update the RGB palette
1103+
extern "C" fn video_set_palette(index: u8, rgb: common::video::RGBColour) {
1104+
// TODO set the palette when we actually have one
1105+
}
1106+
1107+
/// Update all the RGB palette
1108+
unsafe extern "C" fn video_set_whole_palette(
1109+
palette: *const common::video::RGBColour,
1110+
length: usize,
1111+
) {
1112+
// TODO set the palette when we actually have one
1113+
}
1114+
1115+
extern "C" fn i2c_bus_get_info(_i2c_bus: u8) -> common::Option<common::i2c::BusInfo> {
1116+
unimplemented!();
1117+
}
1118+
1119+
extern "C" fn i2c_write_read(
1120+
_i2c_bus: u8,
1121+
_i2c_device_address: u8,
1122+
_tx: common::ApiByteSlice,
1123+
_tx2: common::ApiByteSlice,
1124+
_rx: common::ApiBuffer,
1125+
) -> common::Result<()> {
1126+
unimplemented!();
1127+
}
1128+
1129+
extern "C" fn audio_mixer_channel_get_info(
1130+
_audio_mixer_id: u8,
1131+
) -> common::Result<common::audio::MixerChannelInfo> {
1132+
unimplemented!();
1133+
}
1134+
1135+
extern "C" fn audio_mixer_channel_set_level(_audio_mixer_id: u8, _level: u8) -> common::Result<()> {
1136+
unimplemented!();
1137+
}
1138+
1139+
extern "C" fn audio_output_set_config(_config: common::audio::Config) -> common::Result<()> {
1140+
unimplemented!();
1141+
}
1142+
1143+
extern "C" fn audio_output_get_config() -> common::Result<common::audio::Config> {
1144+
unimplemented!();
1145+
}
1146+
1147+
unsafe extern "C" fn audio_output_data(_samples: common::ApiByteSlice) -> common::Result<usize> {
1148+
unimplemented!();
1149+
}
1150+
1151+
extern "C" fn audio_output_get_space() -> common::Result<usize> {
1152+
unimplemented!();
1153+
}
1154+
1155+
extern "C" fn audio_input_set_config(_config: common::audio::Config) -> common::Result<()> {
1156+
unimplemented!();
1157+
}
1158+
1159+
extern "C" fn audio_input_get_config() -> common::Result<common::audio::Config> {
1160+
unimplemented!();
1161+
}
1162+
1163+
extern "C" fn audio_input_data(_samples: common::ApiBuffer) -> common::Result<usize> {
1164+
unimplemented!();
1165+
}
1166+
1167+
extern "C" fn audio_input_get_count() -> common::Result<usize> {
1168+
unimplemented!();
1169+
}
1170+
1171+
extern "C" fn bus_select(_periperal_id: common::Option<u8>) {
1172+
unimplemented!();
1173+
}
1174+
1175+
extern "C" fn bus_get_info(_periperal_id: u8) -> common::Option<common::bus::PeripheralInfo> {
1176+
unimplemented!();
1177+
}
1178+
1179+
extern "C" fn bus_write_read(
1180+
_tx: common::ApiByteSlice,
1181+
_tx2: common::ApiByteSlice,
1182+
_rx: common::ApiBuffer,
1183+
) -> common::Result<()> {
1184+
unimplemented!();
1185+
}
1186+
1187+
extern "C" fn bus_exchange(_buffer: common::ApiBuffer) -> common::Result<()> {
1188+
unimplemented!();
1189+
}
1190+
1191+
extern "C" fn bus_interrupt_status() -> u32 {
1192+
0
1193+
}
1194+
10161195
/// Get information about the Block Devices in the system.
10171196
///
10181197
/// Block Devices are also known as *disk drives*. They can be read from
@@ -1062,7 +1241,7 @@ pub extern "C" fn block_dev_get_info(device: u8) -> common::Option<common::block
10621241
/// aligned, the BIOS may be able to use a higher-performance code path.
10631242
pub extern "C" fn block_write(
10641243
_device: u8,
1065-
_block: u64,
1244+
_block: common::block_dev::BlockIdx,
10661245
_num_blocks: u8,
10671246
_data: common::ApiByteSlice,
10681247
) -> common::Result<()> {
@@ -1079,7 +1258,7 @@ pub extern "C" fn block_write(
10791258
/// aligned, the BIOS may be able to use a higher-performance code path.
10801259
pub extern "C" fn block_read(
10811260
_device: u8,
1082-
_block: u64,
1261+
_block: common::block_dev::BlockIdx,
10831262
_num_blocks: u8,
10841263
_data: common::ApiBuffer,
10851264
) -> common::Result<()> {
@@ -1097,13 +1276,32 @@ pub extern "C" fn block_read(
10971276
/// aligned, the BIOS may be able to use a higher-performance code path.
10981277
pub extern "C" fn block_verify(
10991278
_device: u8,
1100-
_block: u64,
1279+
_block: common::block_dev::BlockIdx,
11011280
_num_blocks: u8,
11021281
_data: common::ApiByteSlice,
11031282
) -> common::Result<()> {
11041283
common::Result::Err(common::Error::Unimplemented)
11051284
}
11061285

1286+
extern "C" fn block_dev_eject(dev_id: u8) -> common::Result<()> {
1287+
common::Result::Ok(())
1288+
}
1289+
1290+
/// Sleep the CPU until the next interrupt.
1291+
extern "C" fn power_idle() {
1292+
cortex_m::asm::wfe();
1293+
}
1294+
1295+
/// TODO: Get the monotonic run-time of the system from SysTick.
1296+
extern "C" fn time_ticks_get() -> common::Ticks {
1297+
common::Ticks(0)
1298+
}
1299+
1300+
/// We have a 1 kHz SysTick
1301+
extern "C" fn time_ticks_per_second() -> common::Ticks {
1302+
common::Ticks(1000)
1303+
}
1304+
11071305
/// Called when DMA raises IRQ0; i.e. when a DMA transfer to the pixel FIFO or
11081306
/// the timing FIFO has completed.
11091307
#[interrupt]

0 commit comments

Comments
 (0)