custom boot sector virtual CD - operating-system

Following lots of "How to build your own Operating system" tutorials,
I'm supposed to write custom loader to floppy disk boot sector via
#include <sys/types.h> /* unistd.h needs this */
#include <unistd.h> /* contains read/write */
#include <fcntl.h>
int main()
{
char boot_buf[512];
int floppy_desc, file_desc;
file_desc = open("./boot", O_RDONLY);
read(file_desc, boot_buf, 510);
close(file_desc);
boot_buf[510] = 0x55;
boot_buf[511] = 0xaa;
floppy_desc = open("/dev/fd0", O_RDWR);
lseek(floppy_desc, 0, SEEK_CUR);
write(floppy_desc, boot_buf, 512);
close(floppy_desc);
}
I didn't have PC with floppy drive and I prefer to try whole of project on virtual machine via VirtualBox.
So How to write custom boot sector to a virtual CD image that will be invoked by my virtual machine ? :)
If you have any alternative way please suggest it :)

(note: this assumes you are on linux)
Instead of writing to /dev/fd0, which requires a real floppy drive, you could write to some a disk image which could be used to boot VirtualBox. However, you need to pad the file to 1.44MiB, since that's what the typical floppy is.
An even better way would be to first create the bootsector binary (with the 0xAA55 'magic code'), and then do something like dd if=MyBootsectorBin of=Floppy.flp bs=512 count=2880 to create the output file, Floppy.flp. This could be then booted via VirtualBox (or my preference, QEMU, via qemu -fda Floppy.flp).
I'm not sure about virtual CDs, but you can easily create an ISO to write to the disk. The required program for this is mkisofs, and more can be read about it from here.

Related

Raspberry Pico W MicroPython execution freezes a few seconds after disconnecting screen from UART

I got my program running fine as explained at: How can you make a micropython program on a raspberry pi pico autorun?
I'm installing a main.py that does:
import machine
import time
led = machine.Pin('LED', machine.Pin.OUT)
# For Rpi Pico (non-W) it was like this instead apparently.
# led = Pin(25, Pin.OUT)
i = 0
while (True):
led.toggle()
print(i)
time.sleep(.5)
i += 1
When I power the device on by plugging the USB to my laptop, it seems to run fine, with the LED blinking.
Then, if I connect from my laptop to the UART with:
screen /dev/ttyACM0 115200
I can see the numbers coming out on my host terminal correctly, and the LED still blinks, all as expected.
However, when I disconnect from screen with Ctrl-A K, after a few seconds, the LED stops blinking! It takes something around 15 seconds for it to stop, but it does so every time I tested.
If I reconnect the UART again with:
screen /dev/ttyACM0 115200
it starts blinking again.
Also also noticed that after I reconnect the UART and execution resumes, the count has increased much less than the actual time passed, so one possibility is that the Pico is going into some slow low power mode?
If I remove the print() from the program, I noticed that it does not freeze anymore after disconnecting the UART (which of course shows no data in this case).
screen -fn, screen -f and screen -fa made no difference.
Micropython firmware: rp2-pico-w-20221014-unstable-v1.19.1-544-g89b320737.uf2, Ubuntu 22.04 host.
Some variants follow.
picocom /dev/ttyACM0 instead of screen and disconnect with Ctrl-A Ctrl-Q: still freezes like with screen.
If I exit from picocom with Ctrl-A Ctrl-X instead however, then it works. The difference between both seems to be that Ctrl-Q logs:
Skipping tty reset...
while Ctrl-X doesn't, making this a good possible workaround.
The following C analog of the MicroPython hacked from:
https://github.com/raspberrypi/pico-examples/blob/a7ad17156bf60842ee55c8f86cd39e9cd7427c1d/pico_w/blink
https://github.com/raspberrypi/pico-examples/blob/a7ad17156bf60842ee55c8f86cd39e9cd7427c1d/hello_world/usb
did not show the same problem, tested on https://github.com/raspberrypi/pico-sdk/tree/2e6142b15b8a75c1227dd3edbe839193b2bf9041
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
int main() {
stdio_init_all();
if (cyw43_arch_init()) {
printf("WiFi init failed");
return -1;
}
int i = 0;
while (true) {
printf("%i\n", i);
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, i % 2);
i++;
sleep_ms(500);
}
return 0;
}
Reproduction speed can be greatly increased from a few seconds to almost instant by printing more and faster as in:
import machine
import time
led = machine.Pin('LED', machine.Pin.OUT)
i = 0
while (True):
led.toggle()
print('asdf ' * 10 + str(i))
time.sleep(.1)
i += 1
This corroborates people's theories that the problem is linked to flow control: the sender appears to stop sending if the consumer stops being able to receive fast enough.
Also asked at:
https://github.com/orgs/micropython/discussions/9633
Possibly related:
https://forums.raspberrypi.com/viewtopic.php?p=1833725&hilit=uart+freezes#p1833725
What appears to be happening here is that exiting screen (or exiting picocom without the tty reset) leaves the DTR line on the serial port high. We can verify this by writing some simple code to control the DTR line, like this:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
int main(int argc, char **argv)
{
int fd;
int dtrEnable;
int flags;
if (argc < 2) {
fprintf(stderr, "Usage: ioctl <device> <1 or 0 (DTR high or low)>\n");
exit(1);
}
if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
perror("open:");
exit(1);
}
sscanf(argv[2], "%d", &dtrEnable);
ioctl(fd, TIOCMGET, &flags);
if(dtrEnable!=0) {
flags |= TIOCM_DTR;
} else {
flags &= ~TIOCM_DTR;
}
ioctl(fd, TIOCMSET, &flags);
close(fd);
}
Compile this into a tool called setdtr:
gcc -o setdtr setdtr.c
Connect to your Pico using screen, start your code, and then disconnect. Wait for the LED to stop blinking. Now run:
./setdtr /dev/ttyACM0 0
You will find that your code starts running again. If you run:
./setdr /dev/ttyACM0 1
You will find that your code gets stuck again.
The serial chip on the RP2040 interprets a high DTR line to mean that a device is still connected. If nothing is reading from the serial port, it eventually blocks. Setting the DTR pin to 0 -- either using this setdtr tool or by explicitly resetting the serial port state on close -- avoids this problem.
I don't know why it works, but based on advie from larsks:
sudo apt install picocom
picocom /dev/ttyACM0
and then quit with Ctrl-A Ctrl-X (not Ctrl-A Ctrl-Q) does do what I want. Not sure what screen is doing differently exactly.
When quitting, Ctrl-Q shows on terminal:
Skipping tty reset...
and Ctrl-X does not, which may be a major clue.

Where on disk is the BIOS file used by Simics?

(I saw one of my previous posts didn't actually answer the "where's the BIOS file used by simics?" question, so I renamed the previous one and am pulling that question out and making it standalone here.)
I can see the BIOS code for a default "targets\qsp-x86\firststeps.simics" invocation by just stepping through the debugger from the start. But if I want to see the full binary, is there a specific file somewhere I can look at?
you can check "bios" attribute on motherboard image:
simics> board.mb->bios
"%simics%/targets/qsp-x86/images/SIMICSX58IA32X64_1_0_0_bp_r.fd"
You can specify what BIOS image to use by bios_image script parameter to qsp-clear-linux.simics scripts.
Help info for the script:
$ ./simics -h targets/qsp-x86/qsp-clear-linux.simics
System:
bios_image - existing file or NIL
BIOS file.
Default value:
"%simics%/targets/qsp-x86/images/SIMICSX58IA32X64_1_0_0_bp_r.fd"
you can run with your own BIOS like this:
$ ./simics -e '$bios_image=my-bios.bin' targets/qsp-x86/qsp-clear-linux.simics
Now the BIOS is not quite handled consistently with some other things. Typically in Simics, disks and similar things are images. You can list them using list-persistent-images and resolve locations using lookup-file:
simics> list-persistent-images
┌─────────────────────┬────────────┬───────────────────────────────────────────────────────┐
│Image │Unsaved data│File(s) (read-only/read-write) │
├─────────────────────┼────────────┼───────────────────────────────────────────────────────┤
│board.disk0.hd_image │ no│%simics%/targets/qsp-x86/images/cl-b28910-v2.craff (ro)│
│board.disk1.hd_image │ no│ │
│board.mb.sb.spi_image│ yes│%simics%/targets/qsp-x86/images/spi-flash.bin (ro) │
└─────────────────────┴────────────┴───────────────────────────────────────────────────────┘
simics> lookup-file "%simics%/targets/qsp-x86/images/spi-flash.bin"
"/disk1/simics-6/simics-qsp-x86-6.0.47/targets/qsp-x86/images/spi-flash.bin"
The BIOS in the QSP is just loaded straight into target memory for execution. Which is a bit of a cheat for convenience.
Upon searching around, I found the following folder:
C:\Users\yourusername\AppData\Local\Programs\Simics\simics-qsp-x86-6.0.44\targets\qsp-x86\images
Inside that folder are the following 3 files:
SIMICSX58IA32X64_1_0_0_bp_r.fd
SIMICSX58IA32X64-ahci.fd
spi-flash. bin
Both SIMICSX58IA32X64_1_0_0_bp_r. fd and SIMICSX58IA32X64-ahci.fd have UEFI filevolume headers at the start, and a seeming BIOS entry point at the end. The spi-flash. bin seems to have a placeholder of the flash descriptor which would go at the start of the flash, but is mostly empty. So I believe Intel basically either stitches these together in memory, or possibly just uses the spi-flash. bin to allow for "soft strap" configuration or somesuch (since it's a virtual MCH/ICH anyway.)

How to upload binary data (html + favicon) to ESP32 using ESP-IDF?

I am writing a file-serving http server for ESP32 using ESP-IDF and PlatformIO, but I just can't make data upload to SPIFFS work. I am trying to send html and favicon to flash, so it can be served on http.
Code of the server is taken from an example https://github.com/espressif/esp-idf/tree/master/examples/protocols/http_server/file_serving. Noticeable difference is that example project uses only ESP-IDF tools (without platformio) and that in an example data files are in the same directory as source files, where in my projects I have separated directories for /src and /data.
SPIFFS is configured using custom partition table.
I was following instructions from both PlatformIO documents (https://docs.platformio.org/en/latest/platforms/espressif32.html?utm_source=platformio&utm_medium=piohome) as well as from ESP (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#embedding-binary-data).
I have custom partisions.csv file (identical to the example) + changed menuconfig to use it.
In platformio.ini I added:
board_build.partitions = partitions.csv
board_build.embed_txtfiles =
data/favicon.ico
data/upload_script.html
I also changed project CMakeLists file to embed data like this:
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(HTTP-server)
target_add_binary_data(HTTP-server.elf "data/favicon.ico" TEXT)
target_add_binary_data(HTTP-server.elf "data/upload_script.html" TEXT)
/src/CMakeLists stayed unchanged:
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
idf_component_register(SRCS ${app_sources})
But even with all this configuration when I try to use this data in file_server.c like this:
extern const unsigned char favicon_ico_start[] asm("_binary_favicon_ico_start");
extern const unsigned char favicon_ico_end[] asm("_binary_favicon_ico_end");
extern const unsigned char upload_script_start[] asm("_binary_upload_script_html_start");
extern const unsigned char upload_script_end[] asm("_binary_upload_script_html_end");
I get compilation errors
Linking .pio/build/nodemcu-32s/firmware.elf
/home/artur/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/nodemcu-32s/src/file_server.o:(.literal.http_resp_dir_html+0x14): undefined reference to `_binary_upload_script_html_end'
/home/artur/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/nodemcu-32s/src/file_server.o:(.literal.http_resp_dir_html+0x18): undefined reference to `_binary_upload_script_html_start'
/home/artur/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/nodemcu-32s/src/file_server.o:(.literal.favicon_get_handler+0x0): undefined reference to `_binary_favicon_ico_end'
/home/artur/.platformio/packages/toolchain-xtensa32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/nodemcu-32s/src/file_server.o:(.literal.favicon_get_handler+0x4): undefined reference to `_binary_favicon_ico_start'
collect2: error: ld returned 1 exit status
*** [.pio/build/nodemcu-32s/firmware.elf] Error 1
================================================================================= [FAILED] Took 65.20 seconds =================================================================================
I tried changing extern definitions to:
extern const unsigned char favicon_ico_start[] asm("_binary_data_favicon_ico_start");
But it didn't change anything.
Additionally when running "Build Filesystem Image" task I get this error:
*** [.pio/build/nodemcu-32s/spiffs.bin] Implicit dependency `data/favicon' not found, needed by target `.pio/build/nodemcu-32s/spiffs.bin'.
================================================================================= [FAILED] Took 5.70 seconds =================================================================================
The terminal process "platformio 'run', '--target', 'buildfs', '--environment', 'nodemcu-32s'" terminated with exit code: 1.
Any help would be very much appreciated, as I feel that I did everything that the documentation stated.
I suspect you need to declare them as BINARY instead of TEXT. TEXT creates a null-terminated string which probably won't generate the _binary_..._end aliases.
target_add_binary_data(HTTP-server.elf "data/favicon.ico" BINARY)
target_add_binary_data(HTTP-server.elf "data/upload_script.html" BINARY)
Also something's off with your SPIFFS image generation. You know that the CMake macros target_add_binary_data() and idf_component_register(... EMBED_TXTFILES...) embed the stuff only into the application binary, right? You cannot use them add stuff to a pre-generated SPIFFS partition. For that you need to use spiffsgen-py script.
The problem was that I was a little bit confused with the difference between embedding files into an app and sending stuff to SPIFFS partition.
Solution was to move both .html and .ico files from /data to /src. I think the reason behind this is that this code: asm("_binary_favicon_ico_start") can't reference files in other directories, but I am not sure.
I also reversed project CMakeFile to default and added this line to /src/CMakeFile: idf_component_register(SRCS ${app_sources} EMBED_FILES "favicon.ico" "upload_script.html")
I also didn't need to create any filesystem images as SPIFFS partition was only needed for webserver itself.

How to set Linux kernel command line on ARM?

My understanding is that for ARM there are three sources for the kernel boot command line in general:
Those given as CONFIG_CMDLINE in the kernel configuration
Those passed on by the boot loader (typically U-Boot on ARM processors)
Those included in the device tree, under chosen/bootargs
Which one is used depends on kernel configuration parameters. My question is how to choose between these options using kernel configuration?
And can one append to another i.e. can we pass some using CONFIG_CMDLINE and then append hardware specific parameters in device tree?
I'm trying combination 1, 2 AND 3 to begin with but this doesn't compile:
/dts-v1/;
#include "imx6q.dtsi"
#include "imx6q-h.dtsi"
#include "imx6q-m.dtsi"
/ {
model = "A M";
compatible = "a,imx6q-hydra13", "a,imx6q-mercury",
"a,imx6q-hydra", "fsl,imx6q";
};
&ssd_touch {
status = "okay";
};
ERROR AT THIS LINE: chosen {
bootargs = "console=ttymxc1,115200";
};
My understanding is that for ARM there are three sources for the kernel boot command line in general:
That's not accurate for the Linux ARM kernel. The kernel only deals with two "sources", a default kernel command string and a bootloader kernel arguments string.
More details follow.
My question is how to choose between these options using kernel configuration?
You choices may be limited by only "using kernel configuration".
The "additional" command-line configuration choices, i.e. CONFIG_CMDLINE_FROM_BOOTLOADER ("Use bootloader kernel arguments if available"), CONFIG_CMDLINE_EXTEND ("Extend bootloader kernel arguments"), and CONFIG_CMDLINE_FORCE ("Always use the default kernel command string") are only available (since version 3.7) when support for the old ATAGs parameter passing (i.e. CONFIG_ATAGS) is enabled.
However CONFIG_ATAGS does default to y unless explicitly disabled. About a dozen _defconfig files in mainline arch/arm/configs/ do explicitly disable this CONFIG_ATAGS.
But where does the device tree fit in this scheme of things?
The Device Tree is the provider of bootloader kernel arguments.
That is, the bootargs= property in the /chosen node, is the conventional method of providing the command line to the ARM kernel, i.e. when CONFIG_ATAGS is disabled, or either CONFIG_CMDLINE_FROM_BOOTLOADER or CONFIG_CMDLINE_EXTEND are enabled.
The command line is retrieved by the kernel from the Device Tree as a string by early_init_dt_scan_chosen() in drivers/of/fdt.c
Only if CONFIG_CMDLINE_FORCE (with CONFIG_ATAGS) are enabled will the Device Tree bootargs= property be ignored.
You can configure/build the ARM kernel with a default kernel command using CONFIG_CMDLINE in case nothing else managed to set the command line.
A comment in drivers/of/fdt.c documents this.
CONFIG_CMDLINE_EXTEND (with CONFIG_ATAGS) results in a command line that is the concatenation of the Device Tree bootargs= property with the contents of CONFIG_CMDLINE.
However ...
When using U-Boot to boot the Linux kernel, be aware that when the environment variable bootargs is defined, U-Boot will (try to) install that bootargs environment variable (as a property) into the the /chosen node of the loaded Device Tree blob.
If the /chosen node does not exist in the DT, then it is created.
If the bootargs= property does not exist in that DT node, then it is created.
If the bootargs= property already exists in that DT node, then it is overwritten with the U-Boot environment variable.
See fdt_chosen() in common/fdt_support.c.
IOW U-Boot's bootargs environment variable typically becomes the de facto kernel command line.
And can one append to another i.e. can we pass some using CONFIG_CMDLINE and then append hardware specific parameters in device tree?
Only if (a) CONFIG_ATAGS is enabled, and (b) CONFIG_CMDLINE_EXTEND is enabled, and (c) ensure that there is no bootargs variable in U-Boot's environment.
Bottom Line
U-Boot always tries to pass its bootargs variable to the kernel using the Device Tree.
The bootargs= property in the Device Tree is always used by the kernel as the bootloader kernel arguments as mentioned in the arch/arm/Kconfig file.

VS Code with stdin/out .exe server on Windows

I have an LSP server that works fine with VS 2019 IDE. I am now trying to get it to work with VSCode. I wrote a simple extension for VSCode that was working with the server at one point, but VSCode is now not working at all. So, I decided to write a simple C program that simply reads stdin and echos the characters to stderr, not expecting it to work, but to verify that VSCode is at least trying to communicate with the server. As with my original server, this program receives absolutely nothing: VSCode is not sending any packets to the server, and I don't know why.
Here is the simple "echo" server code. All it does is read stdin one character indefinitely then echo the char more or less to stderr, flush()ing each time.
#include <iostream>
#include <stdio.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <io.h>
int main()
{
for (;;)
{
char buf[10];
int readc = _read(0, buf, 1);
fprintf(stderr, "%d\n", buf[0]);
fflush(stderr);
}
return 0;
}
Here is a stripped-down VSCode client extension, derived from the doc, which so happens to provide zero information on spawning a server as a process. This calls spawn() of the server with a window.
export function activate(context: vscode.ExtensionContext) {
const server: vscodelc.Executable = {
command: `C:/Users/kenne/source/repos/ConsoleApplication1/Debug/ConsoleApplication1.exe`,
args: [],
options: {shell: true, detached: true }
};
const serverOptions: vscodelc.ServerOptions = server;
let clientOptions: vscodelc.LanguageClientOptions = {
// Register the server for plain text documents
documentSelector: [{ scheme: 'file', language: 'plaintext' }]
};
const client = new vscodelc.LanguageClient('Antlr Language Server', serverOptions, clientOptions);
console.log('Antlr Language Server is now active!');
client.start();
}
(Via debugging, I figured out that I needed options: {shell: true, detached: true } in the ServerOptions struct to make spawn() create a detached window for the process.) Running the client, the server is spawned with a window, but there is indeed no characters written to the server, even for the simple C "echo" program. In the debugger, I even see that write() is called in the client code, into the json write code, and then into the Node write code. For the VS2019 IDE, this all works perfectly fine.
Does anyone have any ideas on how to get an executable server that uses stdin/stdout to work with VSCode?
The answer is that the tables that the package.json file were messed up. It contains tables required for the server: "activationEvents" describes all the languages supported; "languages" associate a file extension with a language. In addition, the language table is duplicated in the LanguageClientOptions in the activate() function. Without these tables, VSCode may not send an open file request to the LSP server, or even not start the LSP server. In addition, there is a bug in libuv that prevents "windowHidden" to not be processed correctly for Windows. Therefore, the server process cannot be created with a window until fixed. Instead, send server debugging output to a file. The server now works great with VSCode for Antlr2, 3, 4, Bison, and W3C EBNF.