diff --git a/content/posts/0001-immutable-vars-vs-constants-rs.md b/content/posts/0001-immutable-vars-vs-constants-rs.md
new file mode 100644
index 0000000..beaec32
--- /dev/null
+++ b/content/posts/0001-immutable-vars-vs-constants-rs.md
@@ -0,0 +1,337 @@
++++
+draft = false
+date = 2022-10-06T10:30:00+05:30
+title = "Dfferences between Constants and Variables in Rust"
+description = "No really, why do constants exist among \"immutable\" variables?"
+slug = "immutable-vars-vs-constants-rs.md"
+tags = [ "rust", "educational" ]
++++
+
+The reason why the Rust language's developers can advertise features like
+_thread safety_ and _memory safety guarantee_ is because of a fundamental
+design ideology of immutable variables. Immutable variables are the type of
+variables where, once you assign a value, it does not change.
+
+Rust also has constants. So you might wonder "Why does Rust have Immutable
+variables _and_ Constants? Aren't they the same thing?"
+
+In this blog post, I will explain the basics of variables and constants
+in Rust, and how an immutable variable differs from a mutable variable.
+
+## Immutable variables VS Constants
+
+If, like me, Rust is not your first programming language, this confusion is
+bound to occur sooner rather than later--"Why do either immutable variables
+or constants exist in Rust?"
+
+If you have written a simple program in Rust, you will realize that Rust has
+2 types of variables. One is the type which allows changing a value, even
+after it is assigned, called _mutable variables_. The second type is the one
+in question, immutable variables. Unless explicitly specified, Rust assumes
+a variable is immutable. Meaning, once a value is assigned to your variable,
+that value will never be allowed to be changed.
+
+Rust only has one type for constants. The one which makes sense. Immutable by
+default. Once a value is assigned, it is not allowed to change.
+
+## Type inferencing
+
+When you declare a variable in Rust, you do it using the `let` keyword. This
+is different than other low-level languages like C and C++, where you are to
+explicitly specify the data-type of a variable using the appropriate keyword
+like, `int`, `float`, `char`, etc.
+
+Using the `let` keyword is necessary, but specifying a variable's data-type
+is not necessary. You can either leave it to the Rust compiler (`rustc`) to
+take a guess--which hardly misfires--or you can annotate the type yourself.
+
+This guessing that `rustc` does is called "type inferencing".
+
+Type inferencing is absent for constants. It is the job of a programmer to
+provide a type for a constant that is declared.
+
+Take a look at the following code:
+
+Filename: const_example.rs
+
+```rust
+fn main() {
+ let my_var = -128;
+ const MY_CONST = -128;
+}
+```
+
+In here, I am declaring an immutable variable (`my_var`) with the value "-128"
+and a constant (`MY_CONST`) with the same value of "-128". Another similarity
+is that neither of them are type annotated.
+
+Let's try and compile this.
+
+```bash
+$ rustc const_example.rs
+error: missing type for `const` item
+ --> const_example.rs:3:11
+ |
+3 | const MY_CONST = -128;
+ | ^^^^^^^^ help: provide a type for the constant: `MY_CONST: i32`
+
+error: aborting due to previous error
+```
+
+Hmm...
+
+`rustc` is complaining about an error on line 3 (where we declared our
+constant). The highlighted part is the name (`MY_CONST`).
+
+The help states "provide a type for the constant". The help message also
+included a "recommended/suggested type" (`i32`) but it was not applied.
+
+Hence, one of the difference between an immutable variable and a constant in
+Rust is that constants **need** type annotation. Type inferencing is **not**
+applicable to constants.
+
+## Scope of declaration
+
+Another point of difference between an immutable variable and a constant in
+Rust is its scope of declaration.
+
+Constants can be declared globally (before/outside the `main` function).
+Variables, immutable or otherwise, cannot be declared globally.
+
+Let's see this with an example.
+
+Filename: const_example.rs
+
+```rust
+const MY_CONST:i32 = -128;
+let my_var: i32 = -128;
+
+fn main() {
+ println!("{my_var} {MY_CONST}");
+}
+```
+
+As you can see here, I have mostly the same code as above, but I have moved
+both, the variable and the constant declaration, in the global scope.
+
+'tis compile time!
+
+```bash
+$ rustc const_example.rs
+error: expected item, found keyword `let`
+ --> const_example.rs:2:1
+ |
+2 | let my_var: i32 = -128;
+ | ^^^ expected item
+
+error: aborting due to previous error
+```
+
+An error :(
+
+The way I wrote the code should give you a hint. We have an error on the
+2nd line. Our constant is declared on the 1st line.
+
+This means, `rustc` did not see any problems with a constant in the global
+scope. But it does have a problem with our immutable variable if it is
+declared in the global scope.
+
+## Assignable values
+
+Another major difference between variables (immutable or otherwise) and
+constants in Rust is that a constant **cannot** have a value that can be
+calculated **only at run-time**.
+
+What do I mean by this?
+
+Take a look at the following code:
+
+Filename: const_example.rs
+
+```rust
+cat const_example.rs
+fn main() {
+ let pi: f32 = 3.14;
+ const PI_TIMES_TWO: f32 = pi * 2;
+}
+```
+
+In this code, I am declaring an immutable variable (`pi`) and assigning it the
+value of "3.14". Next, I declare a constant, with the same type as `pi`,
+and I assign it the value of `pi * 2`.
+
+Shall we compile?
+
+```bash
+$ rustc const_example.rs
+error[E0435]: attempt to use a non-constant value in a constant
+ --> const_example.rs:3:31
+ |
+3 | const PI_TIMES_TWO: f32 = pi * 2;
+ | ------------------ ^^ non-constant value
+ | |
+ | help: consider using `let` instead of `const`: `let PI_TIMES_TWO`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0435`.
+```
+
+As you can see, even though `pi` is an immutable variable, we get this error.
+This is because `PI_TIMES_TWO` is dependent on the value stored in `pi`
+to determine its own value. This is problematic because the values of
+variables are **not** evaluated at compile-time.
+
+The value assigned to a constant **must not** be calculated/evaluated at
+_run-time_.
+
+## Compile-time vs Run-time
+
+As I just proved, constants can not be assigned a value that will be
+calculated at run-time. That must raise a question if the core reason for the
+existence of immutable variables and constants must be related to the
+differences in run-time and compile-time.
+
+While I am **not** someone who has contributed to the design of the Rust
+language, I am inclined to assume that this might be the reason.
+
+You can use the value assigned to a constant during compile-time, to make
+decisions _while_ the code is being compiled. This can not be done using
+variables, immutable or otherwise.
+
+Let me demonstrate this using an example.
+
+Filename: const_example.rs
+
+```rust
+fn main() {
+ let arr_len_var: usize = 5;
+ const ARR_LEN_CONST: usize = 5;
+
+ let arr_from_const: [i32; ARR_LEN_CONST];
+ let arr_from_var: [i32; arr_len_var];
+}
+```
+
+In this example, I am doing the following:
+
+ 1. Declare an immutable variable with the value "5".
+ 2. Declare a constant with the value "5".
+ 3. Create an empty array, using the value of an immutable variable as the
+ "array size/length".
+ 4. Create another empty array, using the value of a constant as the "array
+ size/length"
+
+If, the jibberish that I just wrote above is correct, we should expect a
+compilation error on the 6th line.
+
+```bash
+$ rustc const_example.rs
+error[E0435]: attempt to use a non-constant value in a constant
+ --> const_example.rs:6:29
+ |
+2 | let arr_len_var: usize = 5;
+ | --------------- help: consider using `const` instead of `let`: `const arr_len_var`
+...
+6 | let arr_from_var: [i32; arr_len_var];
+ | ^^^^^^^^^^^ non-constant value
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0435`.
+```
+
+As expected.
+
+`rustc` has 2 messages for us. The first message--after looking at the
+6th line--is a suggestion for us; to change `arr_len_var` from
+a variable to a constant.
+
+The second message is an error message. It is complaining that the value
+which determines the length of an array, is a "non-constant value".
+
+"But I thought the values of immutable variables could never change?! Does
+that not equate to a _non-constant value_?"
+
+You are correct, but this is something different. You see--this is where I am
+applying my knowledge of what I learnt about compiler design from my
+college--constants are also _evaluated_ at compile-time.
+
+This means, the following line -
+
+```rust
+ const PI: f32 = 3.14;
+ println!("{PI}");
+```
+
+gets replaced with the following in the first few passes of the Rust compiler.
+
+```rust
+ const PI: f32 = 3.14;
+ println!("3.14");
+```
+
+The constant got evaluated (expanded), at compile-time. This will not be be
+the case for a variable, immutable or otherwise.
+
+This is also what happens when we use a constant to determine the length/size
+of an array.
+
+## Shadows
+
+You might know about shadowing in Rust. It refers to the act of referring
+to a different storage/address using the same name.
+
+Below is an example of shadowing:
+
+```rust
+let five = 5;
+let five = 6;
+```
+
+Here, on the first line, we are declaring an immutable variable `five`. It
+assigned the value "5". In the immediate next line, we declare the variable
+`five` again. This time, we assign it "6".
+
+What this does is, when `five` was first declared and assigned the value "5",
+it was given a memory address to store that "5" which we assigned to it.
+Assume this memory address to be `0x01`.
+
+Then, when we declared `five` again; this time with a different value, "6";
+a different memory address was given to our variable `five`. This, new memory
+address stored the value "6". Assume this memory address to be `0x02`.
+
+Now, the older memory address (`0x01`) is not overwritten with "6", instead of
+"5". It is still kept--maybe because this shadow was a local change and we
+will need the previous value again? who knows--intact. But now, when we ask,
+"Hey `five`, what is your assigned value?", it will check the memory location
+`0x02` and give us a value from there; which is "6".
+
+This isn't possible for constants.
+
+ - You can not shadow a constant with a constant (of any type).
+ - You can not shadow a constant with a variable (of any type).
+ - You can not shadow a variable with a constant (of any type).
+
+## Minor nit-picks
+
+A few minor differences between a constant and an immutable variable are as
+follows:
+
+ - Variables are immutable by default, but they can also be mutable, if
+ asked nicely. On the contrary, constants are _always_ immutable. (You cannot
+ use the keyword `mut` next to the `const` keyword.)
+ - To declare a constant, we use the `const` keyword, but to declare an
+ immutable variable, we use the `let` keyword. A variable can be made
+ immutable if, at the time of declaration, the `mut` keyword is used alongside
+ the `let` keyword.
+
+## Conclusion
+
+The intelligent mind who were designing the Rust language were obviously not
+out of their minds when they created variables that default to immutability
+when constants would also exist.
+
+To recap, constants need type annotations, but they can be declared in the
+global scope; values assigned to constants cannot be something that is
+calculated at run-time and they can not be shadowed.
diff --git a/content/posts/0002-convert-mutable-var-to-immutable-rs.md b/content/posts/0002-convert-mutable-var-to-immutable-rs.md
new file mode 100644
index 0000000..1b210c6
--- /dev/null
+++ b/content/posts/0002-convert-mutable-var-to-immutable-rs.md
@@ -0,0 +1,83 @@
++++
+draft = false
+date = 2022-10-09T10:30:00+05:30
+title = "Convert a mutable variable to immutable in Rust"
+description = "Fore_shadowing_"
+slug = "convert-mutable-var-to-immutable-rs.md"
+tags = [ "rust", "educational" ]
++++
+
+The immutability of Rust's variables is a curse and a boon. It is a life saver
+when you are dealing with multi-threaded code. A curse when you want to modify
+the value.
+
+So what do you do now? You add a `mut` after the `let` and make it mutable.
+Some time down the line (haha, get it?), you realize that you need the
+immutability. How do you turn a mutable variable into an immutable variable?
+
+## Shadow it
+
+Most of the times, the solution you are looking for is to shadow the mutable
+variable with the immutable variable.
+
+Take the following code snippet for example:
+
+File: test.rs
+
+```rust
+fn main() {
+ let mut x = 1;
+ x = x + 1;
+ println!("{x}");
+ let x = x;
+ x = x + 3;
+}
+```
+
+And, compiling...
+
+```bash
+$ rustc test.rs
+error[E0384]: cannot assign twice to immutable variable `x`
+ --> test.rs:6:5
+ |
+5 | let x = x;
+ | -
+ | |
+ | first assignment to `x`
+ | help: consider making this binding mutable: `mut x`
+6 | x = x + 3;
+ | ^^^^^^^^^ cannot assign twice to immutable variable
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0384`.
+```
+
+(The unused variable warning from `rustc` is snipped.)
+
+`rustc` is complaining that on line 6, column 5 of "test.rs", it is referring
+to `x` as immutable.
+
+But didn't we declare `x` as `mut` on line 2? Yes, we did.
+
+Now, check the 5th line. There I assigned `x` to itself, making use
+of Rust's _shadowing_ feature. The name `x` is now pointing to a different
+storage that is immutable, but has the value of `&mut x` assigned to it.
+
+{{< notice info >}}
+Please note that in the above explanation, I only use "`&mut x`" to demonstrate
+that the _value_ of mutable variable `x` gets copied. This does not mean that
+the new `x` will point to `&mut x`.
+{{< /notice >}}
+
+## Conclusion
+
+To turn an existing mutable variable into an immutable variable (that Rust
+provides a thread-safe guarantee for), you can shadow the existing mutable
+variable with a new immutable variable.
+
+```rust
+let mut foo; // foo is mutable
+let foo = foo; // foo shadows [mutable foo] and is now immutable
+```
diff --git a/content/posts/0003-visionfive-2-initial-review.md b/content/posts/0003-visionfive-2-initial-review.md
new file mode 100644
index 0000000..f7df745
--- /dev/null
+++ b/content/posts/0003-visionfive-2-initial-review.md
@@ -0,0 +1,322 @@
++++
+draft = false
+date = 2023-02-22T12:36:00+05:30
+title = "Hands on and initial review of the VisionFive 2"
+description = "So RISC-V is a thing, huh."
+slug = "visionfive-2-initial-review.md"
+tags = [ "riscv" ]
++++
+
+Since a long time, RISC-V was in my news feed. I have no idea about RISC-V
+other than that it is an open source ISA (not implementation). That made me
+curious and I wanted to get something RISC-y to understand the hype first-hand.
+
+In August of 2022, I came across the Kickstarter announcement from StarFive
+([here](https://www.kickstarter.com/projects/starfive/visionfive-2)) about the
+VisionFive 2. Following hardware features peaked my interest the *most*:
+
+ - Dual Gigabit Ethernet ports (some _Super early bird_ models have 1x 1000M
+ and 1x 100M ports)
+ - Presence of QSPI flash for `u-boot`
+ - The SBC was available with 8 GB of RAM (that is the minimum for me)
+
+The VisionFive 2 also has one M.2 slot for an NVMe (2280) drive, but it doesn't
+interest me as much. Particularly because it only has the bandwidth of **1x
+PCIe 2.0** lane. Also because I can not afford a _"good"_ NVMe drive at the
+moment.
+
+I don't want to put in a cheap NVMe drive because the cheap ones usually omit
+DRAM. That isn't a problem on a moderately fast computer. But on a computer
+whose CPU (SiFive U74) [allegedly] performs similarly to an ARM A55 core, said
+latency hit is more noticeable.
+
+{{< notice info >}}
+On the note of NVMe, the one thing missing from the hardware perspective is
+the screw to hold the NVMe drive itself.
+{{ notice >}}
+
+
+# Initial software setup
+
+_For now, one is expected to form their opinions on hardware performance based
+on the [Debian image provided the vendor](https://debian.starfivetech.com/)._
+
+**Before you flash the image provided by the vendor, the board firmware
+_needs_ to be updated. Please do that first.**
+
+
+## Updating firmware
+
+The firmware can be easily updated by following these steps:
+
+ 1. Download 3 assets from VisionFive 2's
+ [latest SDK release](https://github.com/starfive-tech/VisionFive2/releases/latest):
+ `sdcard.img`, `u-boot-spl.bin.normal.out`, `visionfive2_fw_payload.img`
+ 2. `sudo dd if=sdcard.img conv=sync status=progress bs=1M of=/dev/`
+ 3. `mkdir temp-dir`
+ 4. `sudo mount /dev/4 temp-dir`
+ 5. `sudo cp u-boot-spl.bin.normal.out visionfive2_fw_payload.img temp-dir/root/`
+ 6. `sudo umount /dev/4`
+ 7. Eject the SD Card from your computer, insert it in VisionFive 2 and power
+ it up. The green LED should start blinking.
+ 8. Plug the network cable on the Ethernet port that is next to the HDMI port.
+ 9. `ssh root@` (passwd: `starfive`)
+ 10. Run the command `cat /proc/mtd` and you should have the following output:
+ ```
+ dev: size erasesize name
+ mtd0: 00020000 00001000 "spl"
+ mtd1: 00300000 00001000 "uboot"
+ mtd2: 00100000 00001000 "data"
+ ```
+ 11. If the partition information is correct, update the `spl` and `uboot`
+ firmware using the following commands:
+ ```
+ flashcp -v u-boot-spl.bin.normal.out /dev/mtd0
+ flashcp -v visionfive2_fw_payload.img /dev/mtd1
+ ```
+
+Done! Now `systemctl poweroff` and flash the vendor's Debian image to your SD
+card and boot it up.
+
+
+## Setup with vendor's image
+
+Although the SD Card image provided by the vendor worked fine for me, people
+have reported two major things missing from their kernel. The modules for
+BTRFS are not built and IPv6 isn't supported either. We will compile the
+kernel soon, but there are other problems with the image that need to be
+tackled first.
+
+
+### Manually expand the root partition
+
+Unlike most images available for the Raspberry Pi, this image does not
+automatically expand the root partition. So first, resize your `/` partition
+using `parted`:
+
+```bash
+root@starfive:~# parted /dev/mmcblk1
+GNU Parted 3.5
+Using /dev/mmcblk1
+Welcome to GNU Parted! Type 'help' to view a list of commands.
+(parted) resizepart 3 100%
+Warning: Partition /dev/mmcblk1p3 is being used. Are you sure you want to
+continue?
+Yes/No? Y
+(parted) q
+Information: You may need to update /etc/fstab.
+```
+
+Resize the filesystem using `resize2fs`:
+
+```bash
+root@starfive:~# resize2fs /dev/mmcblk1p3
+resize2fs 1.46.5 (30-Dec-2021)
+Filesystem at /d[ 192.744328] EXT4-fs (mmcblk1p3): resizing filesystem from 1280507 to
+31186944 blocks
+ev/mmcblk1p3 is mounted on /; on-line resizing required
+old_desc_blocks = 1, new_desc_blocks = 15
+[ 196.934822] EXT4-fs (mmcblk1p3): resized filesystem to 31186944
+The filesystem on /dev/mmcblk1p3 is now 31186944 (4k) blocks long.
+```
+
+Verify the change using the 'df' command. Best reboot now to prevent any
+soft-errors.
+
+
+### Update Debian keyring
+
+To run `apt update` without any errors, the Debian keyring needs to be updated.
+This can be easily remedied by manually downloading the `.deb` file for the
+Debian keyring package from [here](https://packages.debian.org/sid/all/debian-ports-archive-keyring/download) (don't worry, it is architecture agnostic).
+
+Choose your nearest mirror and download it. Then, like any other package, do a
+`dpkg -i debian-ports-archive-keyring*.deb`.
+
+Now, you can `apt update` flawlessly :wink:
+
+
+### OPTIONAL: Update APT sources
+
+**Please note that there is a reason why the APT sources point to a snapshot.
+That is because it is a "known good" state of the packages. I am not
+accountable if your system breaks. I am not a sysadmin.**
+
+But this is what I have done to make sure that I stay up-to-date with any
+developments in the ecosystem.
+
+```bash
+root@starfive:~# cat < /etc/apt/sources.list
+deb http://deb.debian.org/debian-ports sid main
+deb http://deb.debian.org/debian-ports unreleased main
+deb-src http://deb.debian.org/debian sid main
+EOF
+
+root@starfive:~# apt update
+```
+
+
+### MISC
+
+Better do some housekeeping now...
+
+```bash
+root@starfive:~# passwd # use a strong password
+root@starfive:~# userdel -r user
+root@starfive:~# useradd -m -G -s /bin/bash
+root@starfive:~# visudo # I enabled 'NOPASSWD' for my user
+```
+
+
+# Software status of the VisionFive 2
+
+Other than the minor inconvenience of updating the board firmware, setting
+up the vendor's Debian image, everything else seems to mostly work for me.
+
+As new as this SBC is, there already are 5 total offerings for compatible
+images.
+
+ 1. The vendor provided [Debian Sid image](https://debian.starfivetech.com)
+ 2. An "experimental" [Debian Sid image](https://forum.rvspace.org/t/experimental-debian-sid-image/1517)
+ 3. An [Arch Linux image](https://forum.rvspace.org/t/arch-linux-image-for-visionfive-2/1459)
+ 4. [Build your own Debian images](https://forum.rvspace.org/t/build-your-own-debain-images/1881)
+ 5. A community image of [OpenSUSE Tumbleweed](https://en.opensuse.org/HCL:VisionFive2)
+
+The OpenSUSE image, at the time of writing this, _seems_ to be using the latest
+Linux kernel that is available (6.2-rc8) and adding StarFive's patches that are
+for the VisionFive 2. Every other image listed above is using the [StarFive 5.15.0 kernel](https://github.com/starfive-tech/linux/tree/JH7110_VisionFive2_devel).
+
+I have tested images #1, #2 and #3 and I can confirm that the following things
+are working as **_I_** expected:
+
+ - The hardware reset switch works
+ - The GPIO pins work[^1] (along with UART)
+ - Both of the Gigabit Ethernet ports on my board work at the max speed[^2]
+ - All 4 of the front USB 3.0 ports work (didn’t test speed)
+ - HDMI port works[^3]
+
+[^1]: I haven't tested _all the pins_. I used pins 4, 6, 8, 10, and 14. These
+work without any issue so I assume all 40 pins work as intended.
+
+[^2]: You can get 948-ish MBit/s of throughput from each port, which lines up
+with real world performance of other Gigabit NICs. But, sending traffic in from
+one port and receiving it from another port is limited to 500-ish MBit/s of
+throughput due to the way the PHYs are wired ("multiplexed").
+
+[^3]: I don't have a use for display out (on the VF2). I only plugged it in and
+booted the SBC up. For what it is worth, the boot logs show up when connected
+to my 2160p monitor. **No further graphics testing was performed**, since that
+is not my primary aim with this SBC.
+
+{{< notice info >}}
+No offence, but I won't be trying out the OpenSUSE image anytime soon. I
+despise camel case in a _package manager_ of all things. Firefox is called
+`MozillaFirefox`. **WHY?!**
+{{ notice >}}
+
+I am daily driving cwt's Arch Linux image. The kernel in this image is the
+vendor's 5.15.0 Linux kernel. This kernel was compiled to enable the support
+for IPv6 and BTRFS.
+
+The only modification that I had to perform was to add the following line to
+the `/etc/pacman.conf` file:
+
+```
+IgnorePkg = linux-api-headers
+```
+
+I had to do this because the Linux kernel installed is the vendor's 5.15.0
+kernel and the version of the `linux-api-headers` package is `6.1.9`.
+
+{{< notice warning >}}
+This image has an issue with **_rebooting_**. When you try to reboot, the board
+just shuts down. Though, I am looking into fixing this issue.
+{{ notice >}}
+
+---
+
+People on the RVSpace forum reported that the XU4 fan by Hardkernel fits on
+their board ([buy here](https://www.hardkernel.com/shop/cooling-fan-xu4-blue/)).
+So I ordered one. **The fan header on the fan and on the board are
+incompatible.** So I removed the connector from the fan and soldered the wires
+to the jumper wires and inserted it into my GPIO pins. It works now :smile:
+
+With the fan on, and compiling the StarFive's Linux tree for the VisionFive 2
+using `make all -j4`, I never saw the temps go above 42 C. This is quite an
+achievement because I am in India (it's very hot here) and in a room that is
+without an AC.
+
+![btop running on VisionFive 2](/static/images/visionfive_2_review_btop_screenshot.png)
+
+The compilation of StarFive's VisionFive 2 Linux kernel tree using the
+following command completed in 2 hours and 15 minutes. That's _really quick_
+for such a machine!
+
+```bash
+make clean
+make mrproper
+make starfive_visionfive2_defconfig
+ARCH=riscv CFLAGS="-march=rv64imafdc_zicsr_zba_zbb -mcpu=sifive-u74 -mtune=sifive-7-series -O2 -pipe" make all -j4
+```
+
+{{< notice warning >}}
+You will need to patch the file `arch/riscv/Makefile` to compile the kernel
+successfully. Here is the [patch](https://github.com/hexdump0815/linux-starfive-visionfive2-kernel/blob/main/misc.vf2/patches/make-newer-binutils-work.patch).
+{{ notice >}}
+
+
+# My thoughts so far
+
+Since the RISC-V ISA is pretty new, there are still some packages that have
+not been ported yet. As a Neovim user, the biggest hit I received was when
+I noticed that RISC-V support from **upstream** LuaJIT is missing. Though, that
+is [being worked on](https://github.com/LuaJIT/LuaJIT/issues/628).
+
+The Arch Linux maintainer [felixonmars](https://github.com/felixonmars)--who is
+also porting a lot of packages to RISC-V--has made the Neovim package depend on
+`lua51` instead of `luajit` ([relevant git commit](https://github.com/felixonmars/archriscv-packages/commit/7b7f04a28cbe6a04f663a14c914ba4d63b081ede)).
+Neovim wouldn't even install on Debian due to the missing dependency of LuaJIT,
+but on Arch Linux, I can at least install and use Neovim, albeit without the
+traditional Lua support.
+
+I have installed the packages that I have listed below. I haven't tested _all_
+of them, but of what I did test, they work as I expect them to do on my
+Raspbery Pi or on my x86 computer.
+
+```
+android-tools arch-install-scripts aria2 bandwhich base base-devel bat btop cargo-audit cargo-auditable cargo-bloat cargo-depgraph cargo-outdated cargo-spellcheck cargo-watch choose chrony cifs-utils dhcpcd dog dua-cli dust exa fd figlet firewalld gcc git git-lfs groff hd-idle hdparm htop iotop iperf iperf3 linux-firmware lsb-release lsof man-db man-pages mkinitcpio mlocate namcap nano neofetch neovim networkmanager nfs-utils nload nvme-cli opendoas openssh parted paru ripgrep rsync rustup skim smartmontools sudo tealdeer tmux tre tree unrar unzip usbutils wget which wireguard-tools wireless-regdb wol xmlto yt-dlp zsh zsh-autosuggestions zsh-completions zsh-syntax-highlighting
+```
+
+{{< notice note >}}
+**My current workflow does not involve making use of the iGPU in any capacity
+whatsoever.** Hence I will not make any _personal comments_ on it yet. But,
+people have reported some issues with the display output when the SBC is
+connected to a 2160p monitor. On the first day, when I couldn't find my UART
+cable, I had to rely on the display output of the board. So I connected the
+HDMI port to my **2160p** monitor, and, for what it is worth, it at least
+showed me the boot logs. Though, I did see a black screen instead of the login
+manager. I haven't done any further testing in this area since.
+{{< /notice >}}
+
+---
+
+The state of hardware on the SBC seems good enough for my use: as a development
+machine and to build software for RISC-V.
+
+StarFive is [upstreaming](https://rvspace.org/en/project/JH7110_Upstream_Plan)
+software components. The only thing StarFive is not upstreaming is the GPU
+drivers. That commitment is the responsibility of Imagination, as per their
+[post](https://developer.imaginationtech.com/open-source-gpu-driver/).
+
+As of now, I have no gripes as the vendor is not withholding any patches; of
+what is available, works, the vendor is making an effort to upstream as much as
+they can.
+
+To repeat myself for the _nth_ time, of what packages are available,
+they work as one might expect from a PC/laptop. Having such a low cost device
+with minor issues, like the display output not working as intended at 2160p
+resolution, (**in the context of a developer/porting machine**) is a _STEAL_!
+
+I am very happy with it and I will be using this to learn Linux kernel
+development (using :crab:) and help port more ARM64/AMD64 software to it. Let
+me know if you want Rocky Linux on this! :wink:
diff --git a/static/images/visionfive_2_review_btop_screenshot.png b/static/images/visionfive_2_review_btop_screenshot.png
new file mode 100644
index 0000000..2008827
Binary files /dev/null and b/static/images/visionfive_2_review_btop_screenshot.png differ