Following James Molloy’s tutorial

1. You have to download VGABIOS-elpin-2.40 from here https://github.com/nickplee/BochsWatchOS/blob/master/Bochs/bios/VGABIOS-elpin-2.40 and put it to /usr/share/bochs/VGABIOS-elpin-2.40. If you have compiled bochs yourself from the latest SVN Snapshot from SourceForge, the elpin bios is already contained in the bios folder!

2. you have to install bochs and bochs-x

sudo apt-get install bochs bochs-x

3. You have to fix the Makefile

# Makefile for JamesM's kernel tutorials.
# The C and C++ rules are already setup by default.
# The only one that needs changing is the assembler
# rule, as we use nasm instead of GNU as.

SOURCES=boot.o main.o

# 64bit
#ASFLAGS=-felf64
#LDFLAGS=-Tlink.ld -o 64bit
#CFLAGS=-nostdlib -nostdinc -fno-builtin -fno-stack-protector

# 32bit
ASFLAGS=-felf32
LDFLAGS=-Tlink.ld -melf_i386
CFLAGS=-m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector

#ASFLAGS=-felf

#LDFLAGS=-Tlink.ld -melf_i386
#LDFLAGS=-Tlink.ld -m32
#LDFLAGS=-Tlink.ld

all: $(SOURCES) link

clean:
-rm *.o kernel

link:
ld $(LDFLAGS) -o kernel $(SOURCES)

.s.o:
nasm $(ASFLAGS) $<

4.You have to fix bochsrc.txt

megs: 32

#romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
#romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xe0000
romimage: file=/usr/share/bochs/BIOS-bochs-latest

vgaromimage: file=/usr/share/bochs/VGABIOS-elpin-2.40
#vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest

floppya: 1_44=/dev/loop0, status=inserted

boot: a

mouse: enabled=0

clock: sync=realtime

#cpu: ips=500000
cpu: ips=1000000

#display_library: x, options="gui_debug"

log: bochsout.txt

5. when bochs starts and hangs, type

continue

Compiling bochs from source

When installing bochs on Ubuntu, a precompiled bochs version including a debugger is intalled. The debugger kicks in with the first instruction when booting from a floppy. Typing continue makes the debugger continue. When debugging with bochs as an emulator, this gets annoying quickly. People report that the -q option turns off the debugger. This did not work for me. The solution for me was to compile bochs from code without enabling the debugger option and again with the debugging option turned on. Using the version without the debugger speeds up development.

Compiling without debugger

Download the bochs source code from http://bochs.sourceforge.net/getcurrent.html
Scroll down
To download, click the link TAR file containing source code (5061k)

sudo apt-get install libxrandr-dev
sudo apt-get install xorg-dev

Read http://bochs.sourceforge.net/doc/docbook/user/compiling.html

Unzip that downloaded file to a directory
Enter the directory

./configure
make

The folder now contains a bochs executable

Compiling with debugger

Download the bochs source code from http://bochs.sourceforge.net/getcurrent.html
Scroll down
To download, click the link TAR file containing source code (5061k)

sudo apt-get install libxrandr-dev
sudo apt-get install xorg-dev

Read http://bochs.sourceforge.net/doc/docbook/user/compiling.html

Unzip that downloaded file to a directory
Enter the directory

./configure --enable-debugger 
make

The folder now contains a bochs executable

 

Lessons Learned

Own Bootloader vs. GRUB

When writing your own bootloader, you are responsible for finding the kernel binary or bootstrap code and loading it at the correct memory location. GRUB on the other hand will automatically give you a lot of features.

A good GRUB example can be found here http://www.jamesmolloy.co.uk/tutorial_html/.

A good custom bootloader example can be found here https://github.com/cfenollosa/os-tutorial

  • Kernel Binary Loading – Your first bootloader will be very simple. Unless you implement filesystem support, your loader has to read the binary using BIOS calls. It cannot know how large a kernel file is without node information of a filesystem. Hence the sectors read by the BIOS have to be hardcoded and you have to read enough sectors to read your entire kernel in. If you read your kernel only partially, your OS will fail. As your kernel grows, it will outgrow the hardcoded value and you have to update the loader or else the OS will fail. GRUB can read the filesystem on a floppy for example. It knows how large your kernel using the node information provided by the filesystem. No partial loading of your kernel will ever occur.
  • Protected Mode – GRUB can immediately put the CPU into protected mode for you.
  • Graphics Mode – GRUB can set the video mode for you.
  • Multiboot – GRUB can give the user the option to choose which OS to boot. If your OS plays nicely by adhering to the multiboot specification, you can easily have several OS installed on the same machine. A good GRUB multiboot example can be found here http://www.jamesmolloy.co.uk/tutorial_html/.

List of Operating Systems and Links

Table of Operating Systems (Written for educational purposes)

Also visit the operating system topic on github: https://github.com/topics/operating-system and https://archiveos.org/. Another intersting list is https://wiki.osdev.org/Notable_Projects

Name Description Homepage Source Languages
xv6 Unix Version 6 clone https://github.com/mit-pdos/xv6-public https://github.com/mit-pdos/xv6-public  
MMURTL – Message-Based Multitasking Real-Time Kernel Open Source along with the book as PDF http://www.ipdatacorp.com/mmurtl/ https://github.com/bproctor/MMURTL  
tyndur The OS acompanying http://www.lowlevel.eu http://www.lowlevel.eu https://git.tyndur.org/lowlevel/tyndur ASM. C
thor-os     https://github.com/wichtounet/thor-os ASM, C++
kylecs     https://github.com/kylecs/Kernel  
Q-Operating-System     https://github.com/raphydaphy/Q-Operating-System  
eduOS RTWH Aachen educational OS   https://rwth-os.github.io/eduOS/  
Syllable   https://archiveos.org/syllable/    
AtheOS        
Haiku        
Contiki   http://contiki-os.org/ https://github.com/contiki-os/contiki  
intermezzos     https://intermezzos.github.io/  
DexOS   http://dex-os.github.io/    

General Concepts

Links (Intel, AMD)

Links (ARM)

Linux

Unix

Rust

Paging, Memory Management

Read From stdin in Linux Assembler

Reading from stdin means to let the user type text and to consume that text in an application as soon as the user finishes their input by typing enter. Enter will add a linefeed character in Linux

\n = 10 = 0x0A = line feed

The user input first goes into a Linux buffer. You can call a Linux function to retrieve an amount of bytes from that buffer. Once you retrieved bytes, those bytes are subtracted from the Linux buffer so it contains only the input that was not consumed yet. You should always consume the Linux Buffer completely so that it is empty. The reason is that the buffer survives function calls. When you ask the user to input new data on a new occasion, the same input buffer is used. If it was not drained, old input will be read. The second user input might goes behind the existing data. You will expect new data but you are reading the old data first! So always drain the input buffer when asking the user for input, even if you are only interested in the first n characters.

The input is read into a array variable in your application (array of consecutive bytes in the data section). The array variable has to be defined with a fixed length in assembler, e.g. you define a byte array of 100 bytes.

Two things can happen when the user types and sends the input via enter:

  1. The user input from the Linux buffer and the newline fit into the variable in it’s entirety
  2. The user input from the Linux buffer and the newline is too large to fit into the variable.

If the input fits into the buffer, you just have to call the Linux function once which will then drain the entire input buffer. If the input is too large for your variable, you have call the Linux function several times until the Linux Input buffer is empty.

Implementation wise, reading from stdin can be done via int 80h which lets an assembler application call the Linux interrupt 80h. int 80h supports several functions https://www.tutorialspoint.com/assembly_programming/assembly_system_calls.htm. You select the function by putting its id into the eax register.

Reading from stdin has the id 3. ebx remains 0, ecx contains the array variable to put the bytes into. edx contains the amount of bytes to read, which is set to the length of the array variable.

To find out how many characters really were read from the function 3, function 3 will put the amount of bytes read into eax.

The implementation here is taken from https://stackoverflow.com/questions/23468176/read-and-print-user-input-with-x86-assembly-gnu-linux

It will read the first 5 bytes into an array variable and then it will drain the Linux input buffers one byte at a time by reading bytes into a dummy character variable until it sees the newline character. The dummy character is not processed further which means all the rest of the input is just ignored by this solution. In other words this code is only interested in the first 5 bytes and it will ignore the entire rest. The program then proceeds to output the first 5 bytes before it terminates itself.

BUFFER_SIZE equ 5
LINE_FEED equ 10

global _start           ; must be declared for using gcc ???

section .data
    str: times BUFFER_SIZE db 0 ; Allocate buffer of x bytes
    lf:  db 10          ; LF line feed

section .bss
    e1_len resd 1
    dummy resd 1

section .text

_start:                 ; tell linker entry point ???
    ; https://stackoverflow.com/questions/23468176/read-and-print-user-input-with-x86-assembly-gnu-linux

; read using function 3 (sys_read)
    mov eax, 3          ; Read user input into str
    mov ebx, 0          ; |
    mov ecx, str        ; | <- destination
    mov edx, BUFFER_SIZE        ; | <- length
    int 80h             ; \

    mov [e1_len], eax   ; Store number of inputted bytes
    cmp eax, edx        ; all bytes read?
    jb .2               ; yes: ok
    mov bl, [ecx+eax-1] ; BL = last byte in buffer
    cmp bl, LINE_FEED   ; LF in buffer?
    je .2               ; yes: ok
    inc DWORD [e1_len]  ; no: length++ (include 'lf')

; drain the linux input buffer
    .1:                 ; Loop
    mov eax, 3           ; SYS_READ
    mov ebx, 0          ; EBX=0: STDIN
    mov ecx, dummy      ; pointer to a temporary buffer
    mov edx, 1          ; read one byte
    int 0x80            ; syscall
    test eax, eax       ; EOF? eax contains the amount of bytes read
    jz .2               ; yes: ok
    mov al, [dummy]     ; AL = character
    cmp al, LINE_FEED   ; character = LF
    jne .1              ; no -> next character
    .2:                 ; end of loop

; output the array variable using function 4 from int 80h (sys_write)
    mov eax, 4          ; Print 100 bytes starting from str
    mov ebx, 1          ; |
    mov ecx, str        ; | <- source
    mov edx, [e1_len]   ; | <- length
    int 80h             ; \

; return using function 1 from int 80h (sys_exit)
    mov eax, 1          ; Return
    mov ebx, 0          ; | <- return code
    int 80h             ; \
TARGET_DIR := target
MKDIR_P = mkdir -p

all: directories main

main: main.o
	ld target/main.o -o target/main

main.o: main.asm
	nasm -f elf64 main.asm -o target/main.o

clean:
	rm target/main.o target/main

# https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html
.PHONY: directories
directories: ${TARGET_DIR}

${TARGET_DIR}:
	${MKDIR_P} ${TARGET_DIR}

Angular Template-Driven Forms

There are two types of forms in angular
1. reactive (or model-driven) forms
2. template-driven forms

This article is a short reminder on how to find information and on how to work with template-driven forms.

Documentation
The official angular documentation is https://angular.io/guide/forms

Prepare node
Install the latest node Long Term Support (LTS) with nvm.
nvm install --lts

Use the latest version
nvm use node --lts

Start the app
npm start

Create a test application called angular-forms
ng new angular-forms

Generate the data object that is submitted by the form
ng generate class Hero

Create a form component
An Angular form has two parts:
1. an HTML-based template
2. A component class to handle data and user interactions programmatically.

Generate the form component
ng generate component HeroForm

Update the form component’s html

<div class="container">
<h1>Hero Form</h1>
<form (ngSubmit)="onSubmit()" #heroForm="ngForm">

{{diagnostic}}

<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" [(ngModel)]="model.name" name="name" required #spy>
</div>
TODO: remove this: {{spy.className}}

<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" class="form-control" id="alterEgo" [(ngModel)]="model.alterEgo" name="alterEgo">
</div>

<div class="form-group">
<label for="power">Hero Power</label>
<select class="form-control" id="power" [(ngModel)]="model.power" name="power" required>
<option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
</select>
</div>

<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button>

</form>
</div>

 

Update the app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeroFormComponent } from './hero-form/hero-form.component';

@NgModule({
declarations: [
AppComponent,
HeroFormComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

 

Update hero-form.component.ts

import { Component } from '@angular/core';

import { Hero } from '../hero';

@Component({
selector: 'app-hero-form',
templateUrl: './hero-form.component.html',
styleUrls: ['./hero-form.component.css']
})
export class HeroFormComponent {

powers = ['Really Smart', 'Super Flexible',
'Super Hot', 'Weather Changer'];

model = new Hero(18, 'Dr IQ 3000', this.powers[0], 'Chuck OverUnderStreet');

submitted = false;

onSubmit() {
console.log('Submit clicked');
console.log(JSON.stringify(this.model));

this.submitted = true;
}

// TODO: Remove this when we're done
get diagnostic() { return JSON.stringify(this.model); }
}

OnSubmit()
When the submit button is clicked, onSubmit() is called in the form component. To persist, you can create a service and send the object to the backend in json form. The backend then persists the object.

With SpringBoot, you would add a JerseyResource for the endpoint, a JPA repository for the model item and a facade and a service to save the model via the JPA repository.

Arduino and Ethernet Module

Using the Deek-Robot NANO Ethernet Shield V1.0 and the UIPEthernet library, it is possible to add Ethernet capabilities to an Arduino microcontroller. The process is outlined in this excellent article: https://www.tweaking4all.com/hardware/arduino/arduino-enc28j60-ethernet/

A webpage served by the Arduino microcontroller gives you the opportunity to provide a nice, modern user interface to the users of your arduino project from any connected device be it a mobile device such as a smartphone or a desktop PC. You can connect hardware to the arduino which you can then control based on button clicks to the web page you serve to the local network via the Arduino web page. Besides webpages, the Arduino can now provide a REST-API which you could consume from a Angular-Application. REST-APIs allow you to seamlessly integrate the Arduino-Project into existing web applications.

This post documents the individual steps I took to follow the article on tweaking4all.

I used an Arduino UNO, the Deek-Robot NANO Ethernet Shield V1.0 (contains a ENC28J60 chip), Arduino IDE 1.8.9 and the UIPEthernet Sketch from the article on tweaking4all.

First, you have to install the UIPEthernet library into your Arduino IDE. The UIPEthernet library is needed, because the ENC28J60 does not work with the standard Ethernet libraries that ship with the Arduino IDE. The Arduino IDE allows the installation of libraries from Zip-Files. The Zip-File for the UIPEthernet library is conveniently retrieved by downloading the master branch of the Github Repository as a zip file: https://github.com/UIPEthernet/UIPEthernet > Clone or Download > Download zip. Once the zip file is contained on your harddrive, you can import it via the Arduino IDE’s installation feature: In the Arduino IDE, navigate to Sketch > Include Library > Add .ZIP Library. At the top of the drop down list, select the option to “Add .ZIP Library”. If the installation worked, the Arduino IDE will output: Library added to your libraries. Check “include library” menu.

Secondly, wire up the Deek-Robot board to your arduino. The page tweaking4all has a nice image on which pins have to be connected to which pins on the Arduino UNO. You need ground and 5V. My board did not die on 5V so I figure it is true that the Deek-Robot board contains a voltage converter that changes 5V to 3.3V. You have to connect the pins D10, D11, D12, D13 on the Deek-Robot board to the pins 10, 11, 12, 13 on the Arduino board in the same order (D10 is connected to 10, D11 is connected to 11, …). Also, connect a Ethernet cable between the Deek-Robot board and your home network.

Thirdly, you have to set up your router in your home network. Normally, every mac address that connects to the router gets a dynamic IP-Address assigned via DHCP which is a protocol that temporarily leases IP-Addresses to devices. Because DHCP’s use case is to connect a device that only consumes services on the network, the IP-Address is dynamic and not known before the device is connected. Without retrieving the devices IP from the device itself or from your router, you have no way to connect to the device to consume its services. The Arduino sketch contains a mac Address and a fixed IP-Address because we want to connect to the Arduino via a known IP-Address. To prevent DHCP from assigning a dynamic address, a rule is added to the router that assigns a fixed IP-Address to the mac-Address from the sketch. Weather your router is able to add rules and how to add a rule, I can not tell you because I do not know all the routers. Consult your router’s manual to add a rule. Add such a rule, then update the Sketch to contain the mac- and the IP-Address specified in the rule.

As a fourth step, you can now paste the sketch for the UIPEthernet library with correct mac and IP-Address set from tweaking4all into your Arduino IDE, connect your Arduino and Upload the sketch.

Once the sketch has been succesfully uploaded, open the IP address and port 80 in a web browser on a machine that is connected to your home network. Before connecting via the browser, you can open a serial terminal to the arduino. The Arduino will output information about a established connection into the serial terminal. Your browser will execute a GET-Request towards the Arduino Server and it will retrieve the small HelloWorld HTML-page that the sketch predefines. After serving the page, the connection is terminated by the Arduino server.

That is it! Basically if you know how to connect the board, install the library, set up a DHCP rule and after reading the article on tweaking4all, you can make your Arduino available in your home network. A downside of this approach is that the Deek-Robot board uses pins 10, 11, 12, 13 on your arduino. They are blocked for other boards. The next steps would be to figure out how to serve more resources than just the hello world webpage! How would you serve several pages connected to each other via hyperlinks for example? How do you server static resources such as CSS, JS and image files? Nevertheless, connecting the Arduino to the Ethernet network, enables your Arduino projects from your smartphone! A lot is possible. Have fun with your projects and thank you for reading this article.