···11----
22-title: "Secret Entrance"
33-published: 2025-12-16
44-draft: false
55----
66-77-88-99-# Part 1
1010-1111-We are given line seperated operations that happen on a 100 pin circular dial. The dial starts at 50 and we are to output, how many times the dial stops at 0!
1212-1313-We first, as expected, just take in the input and initialise variables to store current dial position and total number of times the dial has stopped at 0.
1414-1515-```rust title="setup"
1616-use std::fs::read_to_string;
1717-fn main() {
1818- let contents = read_to_string("./input.txt").unwrap();
1919- let mut curr: i32 = 50;
2020- let mut tot = 0;
2121-2222- <<logic_loop>>
2323-2424- println!("Password: {tot}");
2525-}
2626-```
2727-2828-We go through each line of input, and parse it. Our input is in the form -"L50" where the first character is the direction in which the dial is to be rotated and the rest is the amplitude.
2929-3030-```rust title="logic_loop"
3131-for line in contents.lines() {
3232- let words: Vec<char> = line.chars().collect();
3333- let dir = words[0];
3434- let amp: String = words[1..].iter().collect();
3535- let amp: i32 = amp.parse().unwrap();
3636-3737- <<rotate_dial>>
3838-}
3939-```
4040-4141-Now that we have both the dir and the amp, we can modify the dial position.
4242-4343-```rust title="rotate_dial"
4444-if dir == 'L' {
4545- curr -= amp;
4646-} else {
4747- curr += amp;
4848-}
4949-5050-<<loopback>>
5151-```
5252-5353-The value of curr could have gone above 99 or below 0, which we need to rectify.
5454-5555-```rust title="loopback"
5656-if curr < 0 {
5757- curr = 100 + curr;
5858-}
5959-6060-curr = curr % 100;
6161-6262-<<count_zeros>>
6363-```
6464-6565-Now that we have the current position of the dial, we only need to check if it currently points at 0, and increment `tot`, if it does.
6666-6767-```rust title="count_zeros"
6868-if curr == 0 {
6969- tot += 1;
7070-}
7171-```
7272-7373-We have the final program-
7474-7575-```rust title="Full Program"
7676-use std::fs::read_to_string;
7777-fn main() {
7878- let contents = read_to_string("./input.txt").unwrap();
7979- let mut curr: i32 = 50;
8080- let mut tot = 0;
8181-8282- for line in contents.lines() {
8383- let words: Vec<char> = line.chars().collect();
8484- let dir = words[0];
8585- let amp: String = words[1..].iter().collect();
8686- let amp: i32 = amp.parse().unwrap();
8787-8888- if dir == 'L' {
8989- curr -= amp;
9090- } else {
9191- curr += amp;
9292- }
9393-9494- if curr < 0 {
9595- curr = 100 + curr;
9696- }
9797-9898- curr = curr % 100;
9999-100100- if curr == 0 {
101101- tot += 1;
102102- }
103103- }
104104-105105- println!("Password: {tot}");
106106-}
107107-```
108108-109109-110110-# Part 2
111111-112112-Another complication has been added to our little problem! Now we not only need to say how many times the dial stopped at 0, but also how many times it crossed it!
113113-114114-We add two new variables that are going to help us! `prev` and `cross`. We are going to keep `tot` and its related logic and add onto it!
115115-116116-```rust
117117-// In setup
118118-let mut prev: i32 = 50;
119119-let mut cross = 0;
120120-```
121121-122122-If the amplitude is >100, that means atleast one full rotation, therefore, atleast oe crossing of 0! We can figure out the number of crossing here using division. We also bring the value of amp to the range [0, 99].
123123-124124-```rust
125125-cross += amp / 100;
126126-let amp = amp % 100;
127127-```
128128-129129-An easy way to detect a crossing is to check if the difference in `curr` and `prev` is opposite to what we expected.
130130-131131-For example, let's say dial position is at `5` and we get input `L10`, as the `dir` is `L`, the dial position should decrease, that is, `curr` < `prev`, but as the `amp` was 10, the new dial position becomes `95`. Now, `curr` (95) > `prev` (5).
132132-133133-Detecting for this, and similarly `curr` < `prev` for `R`, we can check if there was a crossing on this move!
134134-135135-One thing we need to keep in mind is to ignore those where either `curr` or `prev` were 0, as they would have been already counted by `tot`!
136136-137137-:::duck
138138-Also, do remember to set `prev = curr` at the end, you don't want to know how much time I spent debugging this!
139139-:::
140140-141141-```rust
142142-if ((dir == 'L' && prev < curr) || (dir == 'R' && prev > curr)) && curr != 0 && prev != 0 {
143143- cross += 1;
144144-}
145145-146146-prev = curr;
147147-```
148148-149149-Our final program-
150150-151151-```rust title="main.rs"
152152-use std::fs::read_to_string;
153153-154154-fn main() {
155155- let contents = read_to_string("./input.txt").unwrap();
156156-157157- let mut curr: i32 = 50;
158158- let mut prev: i32 = 50;
159159- let mut tot = 0;
160160- let mut cross = 0;
161161-162162- for line in contents.lines() {
163163- let words: Vec<char> = line.chars().collect();
164164- let dir = words[0];
165165- let amp: String = words[1..].iter().collect();
166166- let amp: i32 = amp.parse().unwrap();
167167-168168- cross += amp / 100;
169169- let amp = amp % 100;
170170-171171- if dir == 'L' {
172172- curr -= amp;
173173- } else {
174174- curr += amp;
175175- }
176176-177177- if curr < 0 {
178178- curr = 100 + curr;
179179- }
180180- curr = curr % 100;
181181-182182- if curr == 0 {
183183- tot += 1;
184184- }
185185- if ((dir == 'L' && prev < curr) || (dir == 'R' && prev > curr)) && curr != 0 && prev != 0 {
186186- cross += 1;
187187- }
188188-189189- prev = curr;
190190- }
191191- println!("Password: {}", cross + tot);
192192-}
193193-```
194194-
-188
src/content/aoc/2025/02.md
···11----
22-title: "Gift Shop"
33-published: 2025-12-18
44-draft: false
55----
66-77-We are given comma-separated ranges of numbers that we have to check, we sum all the numbers which are n repeating blocks, for example, 123123 has n = 2, and block = 123, similarly, 111, has n = 3, and block = 1! Part 1 has n = 2, and Part 2 can have any value as n! So we can just directly solve Part 2 (although I did solve Part 1 as a standalone problem first). Let's get started…
88-99-1010-# Boilerplate
1111-1212-```rust
1313-use std::fs;
1414-1515-fn main() {
1616- let input = fs::read_to_string("./input.txt").unwrap();
1717- let ranges = input.split(",");
1818- let mut sum = 0;
1919- for range in ranges {
2020- let mut nums = range.split("-");
2121-2222- let start: u64 = nums.next().unwrap().trim().parse().unwrap();
2323- let end: u64 = nums.next().unwrap().trim().parse().unwrap();
2424-2525- for i in start..=end {
2626- let i_str = i.to_string();
2727-2828- if check(i_str) {
2929- sum += i;
3030- }
3131- }
3232- }
3333- println!("Sum: {sum}");
3434-}
3535-```
3636-3737-We parse the input, and send the number (as a string) to `check` function for the actual logic.
3838-3939-4040-# check
4141-4242-```rust title="check"
4343-fn check(i_str: String) -> bool {
4444- for check_len in 1..i_str.len() {
4545- if check_n(&i_str, check_len) {
4646- return true;
4747- }
4848- }
4949- return false;
5050-}
5151-```
5252-5353-We start with n=1 and go up to the length of the string checking if it has 'n' repeating blocks!
5454-5555-5656-# check<sub>n</sub>
5757-5858-check<sub>n</sub> actually performs the logic-
5959-6060-1. It is obviously not going to be 'n' repeating blocks if the length of the string is not even divisible by n!
6161-6262- ```rust
6363- if i_str.len() % check_len != 0 {
6464- return false;
6565- }
6666- ```
6767-6868-2. Setup block content
6969-7070- ```rust
7171- let nums = i_str.char_indices();
7272-7373- let mut curr = String::new();
7474- let comp = &i_str[0..check_len];
7575- ```
7676-7777-3. Now we append each character to `curr`, and on every 'n'th character, we compare `curr` and `comp`, if it is different, we return false, otherwise we clear `curr` and continue.
7878-7979- ```rust
8080- for (id, c) in nums {
8181- if id % check_len == 0 && id != 0 {
8282- if comp != curr {
8383- return false;
8484- }
8585- curr = String::new();
8686- }
8787- curr.push(c);
8888- }
8989- ```
9090-9191-4. We also need to check the last block
9292-9393- ```rust
9494- if comp != curr {
9595- return false;
9696- }
9797- ```
9898-9999-5. We return true, if all blocks are same
100100-101101- ```rust
102102- true
103103- ```
104104-105105-Our Final check<sub>n</sub> function-
106106-107107-```rust title="check_n"
108108-fn check_n(i_str: &str, check_len: usize) -> bool {
109109- if i_str.len() % check_len != 0 {
110110- return false;
111111- }
112112- let nums = i_str.char_indices();
113113-114114- let mut curr = String::new();
115115- let comp = &i_str[0..check_len];
116116- for (id, c) in nums {
117117- if id % check_len == 0 && id != 0 {
118118- if comp != curr {
119119- return false;
120120- }
121121- curr = String::new();
122122- }
123123- curr.push(c);
124124- }
125125- if comp != curr {
126126- return false;
127127- }
128128- true
129129-}
130130-```
131131-132132-Which gives us our final program-
133133-134134-```rust title="main.rs"
135135-use std::fs;
136136-137137-fn main() {
138138- let input = fs::read_to_string("./input.txt").unwrap();
139139- let ranges = input.split(",");
140140- let mut sum = 0;
141141- for range in ranges {
142142- let mut nums = range.split("-");
143143-144144- let start: u64 = nums.next().unwrap().trim().parse().unwrap();
145145- let end: u64 = nums.next().unwrap().trim().parse().unwrap();
146146-147147- for i in start..=end {
148148- let i_str = i.to_string();
149149-150150- if check(i_str) {
151151- sum += i;
152152- }
153153- }
154154- }
155155- println!("Sum: {sum}");
156156-}
157157-fn check(i_str: String) -> bool {
158158- for check_len in 1..i_str.len() {
159159- if check_n(&i_str, check_len) {
160160- return true;
161161- }
162162- }
163163- return false;
164164-}
165165-fn check_n(i_str: &str, check_len: usize) -> bool {
166166- if i_str.len() % check_len != 0 {
167167- return false;
168168- }
169169- let nums = i_str.char_indices();
170170-171171- let mut curr = String::new();
172172- let comp = &i_str[0..check_len];
173173- for (id, c) in nums {
174174- if id % check_len == 0 && id != 0 {
175175- if comp != curr {
176176- return false;
177177- }
178178- curr = String::new();
179179- }
180180- curr.push(c);
181181- }
182182- if comp != curr {
183183- return false;
184184- }
185185- true
186186-}
187187-```
188188-
-145
src/content/aoc/2025/03.md
···11----
22-title: "Lobby"
33-published: 2025-12-24
44-draft: false
55----
66-77-Entire question [here](https://adventofcode.com/2025/day/3).
88-99-We are given several line separated strings of numbers (0-9) and a number `n`, for each string, we have two select two characters, appending which, in order, produces the largest number; and return their sum.
1010-1111-For example, in the string "97856483" and n = 2, our answer is 98. In "811111111111119", we have 89!
1212-1313-The only differentiating part in part 1 and part 2 is n. Part 1 has n = 2, and part 2 has it equal to 12.
1414-1515-Let's get started then, and get done with the boilerplate first.
1616-1717-```rust
1818-use std::fs;
1919-2020-fn main() {
2121- let input = fs::read_to_string("./sample.txt").unwrap();
2222- let mut sum = 0;
2323-2424- for line in input.lines() {
2525- let num = parse(&line, 12);
2626- sum += num;
2727- }
2828- println!("Final number: {sum}");
2929-}
3030-```
3131-3232-The real meat is in the parse function!
3333-3434-Let us go through the logic.
3535-3636-1. We store three variables, sum, last<sub>index</sub>, and placeholder.
3737-3838- 1. `sum` is the running sum for the current line.
3939- 2. `last_index`- We only search after last<sub>index</sub>.
4040- 3. `placeholder`- To store the place value we are currently searching for. For example, 10s, 100s, etc.
4141-4242- ```rust
4343- fn parse(line: &str, pl: u32) -> u64 {
4444- let mut sum: u64 = 0;
4545- let mut last_index: isize = -1;
4646- let mut placeholder: i32 = pl as i32 - 1;
4747-4848- <<logic>>
4949- }
5050- ```
5151-5252-2. Now onto the loop!! We go through each character in the line, starting after the last<sub>index</sub> and check if the current char is equal to curr<sub>num</sub> (curr<sub>num</sub> starts from 9 and ticks down each time we can't find that number in the line). One thing to note is the range in which we check the chars, starting from `last_index + 1` to length of the line - placeholder!
5353-5454- ```rust
5555- while placeholder >= 0 {
5656- let mut found = false;
5757-5858- for curr_num in (0u64..=9).rev() {
5959- for (i, c) in line.chars().enumerate() {
6060- if i as isize <= last_index {
6161- continue;
6262- }
6363-6464- if let Some(num) = c.to_digit(10) {
6565- if num as u64 == curr_num
6666- && i < line.len() - placeholder as usize
6767- {
6868- last_index = i as isize;
6969- sum += curr_num * 10_u64.pow(placeholder as u32);
7070- placeholder -= 1;
7171- found = true;
7272- break;
7373- }
7474- }
7575- }
7676-7777- if found {
7878- break;
7979- }
8080- }
8181-8282- if !found {
8383- break;
8484- }
8585- }
8686-8787- sum
8888- ```
8989-9090-We have our final program
9191-9292-```rust title="main.rs"
9393-use std::fs;
9494-9595-fn main() {
9696- let input = fs::read_to_string("./sample.txt").unwrap();
9797- let mut sum = 0;
9898-9999- for line in input.lines() {
100100- let num = parse(&line, 12);
101101- sum += num;
102102- }
103103- println!("Final number: {sum}");
104104-}
105105-fn parse(line: &str, pl: u32) -> u64 {
106106- let mut sum: u64 = 0;
107107- let mut last_index: isize = -1;
108108- let mut placeholder: i32 = pl as i32 - 1;
109109-110110- while placeholder >= 0 {
111111- let mut found = false;
112112-113113- for curr_num in (0u64..=9).rev() {
114114- for (i, c) in line.chars().enumerate() {
115115- if i as isize <= last_index {
116116- continue;
117117- }
118118-119119- if let Some(num) = c.to_digit(10) {
120120- if num as u64 == curr_num
121121- && i < line.len() - placeholder as usize
122122- {
123123- last_index = i as isize;
124124- sum += curr_num * 10_u64.pow(placeholder as u32);
125125- placeholder -= 1;
126126- found = true;
127127- break;
128128- }
129129- }
130130- }
131131-132132- if found {
133133- break;
134134- }
135135- }
136136-137137- if !found {
138138- break;
139139- }
140140- }
141141-142142- sum
143143-}
144144-```
145145-
-128
src/content/posts/perpetual.md
···11----
22-title: "Musings"
33-published: 2025-12-07
44-draft: true
55-description: '...'
66-tags: ["musings"]
77----
88-99-Am I alone?
1010-1111-I think so
1212-1313-But who am I?
1414-1515-You are me
1616-1717-And who is speaking?
1818-1919-I am you
2020-2121-Well that doesn't make any sense
2222-2323-It doesn't have to
2424-2525-But it has to! What am I supposed to do if nothing makes sense?
2626-2727-You are not supposed to do anything
2828-2929-How am I even supposed to live then? If I am supposed to do nothing, what am I even here for?
3030-3131-You use the word "supposed" a lot, don't you?
3232-3333-…
3434-3535-One of the quieter ones huh
3636-3737-I am not quiet!
3838-3939-Well, to answer your question, again you are not supposed to do anything but tha-
4040-4141-So I am not even supposed to live then?
4242-4343-Let me complete first, yes you are not supposed to do anything but that is different than "supposed to do nothing" you know
4444-4545-You are just confusing me, if I am not supposed to do anything, what is the point of doing ***ANYTHING***?
4646-4747-Again, there is no point
4848-4949-So it doesn't matter if I die?
5050-5151-Death is the only certainty in life as you people say, why do you think yours will be any different this time
5252-5353-Even my parents won't remember me?
5454-5555-They will, but they too will move on
5656-5757-No they won't! They love me!
5858-5959-Yes they love you, but they WILL move on, the same way you moved on from that doll you loved as a kid
6060-6161-I just grew up…
6262-6363-So will they. The same way you continue to live on, they will too
6464-6565-If there is no point to anything then why even bother doing anything? Why should I eat? Why should I sleep? Why should I love? Why should I care?
6666-6767-The fact that there is no point, is THE entire point. Nothing needs to make sense because sense is not needed for you to function. You fear things out of your control, that is your bane
6868-6969-Of course I do! I am a human you know, of course I am going to fear things that can hurt me
7070-7171-But you fear things that have no impact on you. You dress up just so people on the street don't mock you, you fear being yourself just so others will like you. Just consider that girl you have a crush on, you analyse every move, both yours and hers, trying to find a signal that may or may not even be there!
7272-7373-So what! Should I just stop caring about others? If nothing matters, should I just go around punching random kids on the street!
7474-7575-You are still doing the same, just dumping the responsibilty of that answer on me
7676-7777-I can't even ask you a question?!
7878-7979-What do you think you have been doing till now :) The problem isn't you asking me a question, the problem is you asking an answer. You refuse to think about it, you refuse to take on that burden because you are afraid of what your answer could be
8080-8181-But if others hate me, what will I do? How will I live completely alone?
8282-8383-Why do you live?
8484-8585-What do you mean why do I live?
8686-8787-I mean why are you still alive, if you don't have any hope, why haven't you killed yourself?
8888-8989-Because people I care about, my parents, my friends, would be sad if I died
9090-9191-So you live for others?
9292-9393-Isn't that good enough?
9494-9595-You are making excuses, just like you always do. Pretending to be the forever victim, the one who couldn't have done any wrong, the one who fate has robbed at every turn.
9696-9797-…
9898-9999-You like having othes depend upon you, even if for the very smallest of the things, it satisfies that twisted little mind of yours, it makes you feel worth something.
100100-101101-That could be…
102102-103103-If you want real happiness, you have got to find it for yourself, not wait for somebody to give it to you! Isn't that what you have been doing?
104104-105105-I am worthless, nobody needs me.
106106-107107-You seek your value in the perce
108108-109109-AHHH SHUT UP!!!
110110-111111-ption of others. Do you fear being alone? You're afraid that you will lose your identity if others leave you
112112-113113-JUST LEAVE ME ALONE!! HOW CAN A FLOATING VOICE EVEN DARE TELL ME THAT!!
114114-115115-You're afraid that you will disappear from the mind of others. Each conversation they have that doesn't involve you, each inside joke that you are not part of, each knowing glance that you can't decipher scares you. Isn't that right?
116116-117117-No it is not, I want to be alone, I don't feel emotions since a long time, I have not cried in 5 years, I have always been alone and I like being alone. That is the reason I left my home and came to a new city for school. I want to be alone.
118118-119119-Was it really that or did you just want the attention to yourself? Tired of the fact that your brother was the one your mother has always liked more? What about when your entire family had that car crash and your mother kept looking for him, not even bothering to look at you? Or how your father was so focused on getting your mother in the hospital that he just left you with a stranger, with a broken and bleeding foot and a detached ear? How old were you then, 13?
120120-121121-I did not do it for attention. And anyways, nowadays they DO focus more on me!
122122-123123-Yes, after your brother disappointed them for 5 years straight. Huh, the same amount of years that took you to regain their trust after exactly two lies!! Do you think things will remain the same once he regains it too, as he is currently doing, or will they revert back to how things actually were? A 3 year old boy getting beaten up because he wanted his favourite song to play, a 8 year old getting beaten because his hand writing is not that good, a 15 year old getting beaten up because somebody stole the handle grips from his bicycle?
124124-125125-Even if they do, I don't care, things have always been like that and I have made my peace with it
126126-127127-Have you really?
128128-
···11----
22-title: "Guix is just better"
33-published: 2025-11-18
44-draft: true
55-description: 'A signature look of superiority'
66-tags: ["guix","linux"]
77----
88-99-1010-1111-# Déjà vu?
1212-1313-The three people that may have read a previous iteration of this blog on the previous iteration of this website, that I accidentaly nuked while changing the framework from hugo to astro, are requested to pretend this is some fresh piece of writing.
1414-1515-:::caution
1616-Yes, I am THAT stupid
1717-:::
1818-1919-Regardless, if you want to hear me ramble more about a topic I don't fully understand, continue on!!
2020-2121-2222-# What is Guix?
2323-2424-In its own [words](https://guix.gnu.org/en/about/),
2525-2626-> The GNU Guix package and system manager is a free software project developed by volunteers around the world under the umbrella of the GNU Project.
2727-2828-> Guix System is a distribution of the GNU operating system. It uses the Linux-libre kernel, and support for the Hurd is being worked on. As a GNU distribution, it is committed to respecting and enhancing the freedom of its users. As such, it adheres to the GNU Free System Distribution Guidelines.
2929-3030-> GNU Guix provides state-of-the-art package management features such as transactional upgrades and roll-backs, reproducible build environments, unprivileged package management, and per-user profiles. It uses low-level mechanisms from the Nix package manager, but packages are defined as native Guile modules, using extensions to the Scheme language—which makes it nicely hackable.
3131-3232-> Guix takes that a step further by additionally supporting stateless, reproducible operating system configurations. This time the whole system is hackable in Scheme, from the initial RAM disk to the initialization system, and to the system services.
3333-3434-Guix is a distro intended for geeks, incidentally pronounced that way too. There is no way to sugarcoat it, there is an inherent difficulty to these things, if you find Arch difficult to use, you shouldn't use Nix, if you can't use Nix, you should probably stay away from Guix, and if you can master Guix… you still won't be able to use Windows without borking it!
3535-3636-3737-## Story Time
3838-3939-I have been on linux since I was 13 (2018) and in my 7 years of using it, it has been exactly 3 times when I was hugely excited about linux itself, not some tooling related to it or any work I did using it, linux itself.
4040-4141-4242-### The Beginnings
4343-4444-First was when I discovered Linux, in the form of Ubuntu which at that time had not gone down the drain. My laptop was a brand-new Dell laptop with i3 6th gen CPU, 4 gigabytes of RAM and a whopping 1 TB of Hard Disk capacity, I had worked with PC's before this (I learned how to play *Surma Sarela* and *Bhalu Lagdu Bhanuli* on my father's computer when I was 3) but it had been mostly superficial with only a little dabbling in the Front-End development space due to the encouragement from my *Chachu* (Uncle). But I digress, as you would expect this did not lead to me being an expert in all things computer and I borked that laptop many times on Windows. Eventually I read a little about Ubuntu on the internet and figured well why not?! What do I have to lose! The process was not very difficult and I managed to install it. Suprisingly, the transition was very smooth (it speaks to its quality that even a 13 year old ME was able to install and use it) and I would wait for every update, and this would lead to me becoming addicted to this excitement, becoming the ill-fated **Distro-Hopper**.
4545-4646-4747-### Mid-Life Crisis
4848-4949-When 2020 with its Covid Craziness<sup>TM</sup> hit, I found myself with a lot of free time on my hand
5050-
-152
src/content/posts/xv6-intro/index.md
···11----
22-title: "xv6 - Introduction"
33-published: 2026-01-02
44-draft: false
55-description: 'Introducing the xv6 kernel'
66-series: 'xv6'
77-tags: ["xv6","os"]
88----
99-1010-1111-1212-# Why??
1313-1414-I am currently going through the book ***Operating Systems: Three Easy Pieces***, and the next step after completing the first piece, Virtualisation, is to go through the xv6 kernel. The xv6 kernel had two implementations, the x86 one and RISC-V one. As the x86 one is now unmaintained and on recommendation of a mentor, I am using [xv6-riscv](https://github.com/mit-pdos/xv6-riscv)! So without further ado, let's get started.
1515-1616-1717-# The xv6 Kernel
1818-1919-- Based on Unix kernel
2020-- Created by MIT for educational purposes
2121-- Implemented for RISC-V
2222-- Multicore
2323-- ~6000 lines of code (C and Assembly)
2424-2525-2626-## Features
2727-2828-- Processes
2929-- Virtual Address Spaces
3030- - Page Tables
3131-- Files and Directories
3232-- Pipes
3333-- Multitasking
3434- - Time-Slicing
3535-- 21 system calls
3636-3737-3838-## User Programs
3939-4040-- sh
4141-- cat
4242-- echo
4343-- grep
4444-- kill
4545-- ln
4646-- ls
4747-- mkdir
4848-- rm
4949-- wc
5050-5151-5252-## What is missing?
5353-5454-All the complexity of a "real" operating system is missing. For example, UserID, file protections, IPC, "mount"able filesystem, etc.
5555-5656-5757-## SMP: Shared Memory Multiprocesser
5858-5959-CPU = core = HART
6060-6161-Main memory (RAM) is shared and is of size 128 Mbytes
6262-6363-6464-## Supported Devices
6565-6666-- UART (Serial Comm. Tx <=> Rx)
6767-- Disk
6868-- Timer Interrupts
6969-- PLIC: Platform Level Interrupt Controller
7070-- CLINT: Core Local Interrupt Controller
7171-7272-7373-## Memory Management
7474-7575-- Page Size = 4096 bytes (`#define PGSIZE`)
7676-- Single Free List
7777-- No variable sized allocation
7878-- No "malloc"
7979-- Page Tables-
8080- - Three Levels
8181- - One table per process + One table for Kernel
8282- - Pages marked - R/W/X/U/V
8383-8484-8585-## Scheduler
8686-8787-- Round Robin
8888-- Size of TimeSlice is fixed (1,000,000 cycles)
8989-- All cores share one "Ready Queue"
9090-- Next TimeSlice may be on a different core
9191-9292-9393-## Boot Sequence
9494-9595-- QEMU
9696- - Loads kernel code at a fixed address (0x8000-0000)
9797- - Starts all cores running
9898-- No bootloader/boot-block/BIOS
9999-100100-101101-## Locking
102102-103103-- Spin Locks
104104-- `sleep()` & `wakeup()`
105105-106106-107107-## "Param.h"
108108-109109-- Fixed Limits (like no. of processes, no. of open files, etc)
110110-- Several Arrays ("`kill(pid)`" => Linear search of Processes array)
111111-112112-113113-## User Address Space
114114-115115-
116116-117117-Arguments (argc, argv) will be placed on the stack before the program begins execution.
118118-119119-120120-## RISC-V Virtual Addresses
121121-122122-- Multiple Schemes are available
123123- - Sv32 -> Used for 2-level Page Tables
124124- - Sv39 -> For 3-levels
125125- - Sv48 -> For 4-levels!
126126-- xv6 uses Sv39
127127-- VA Size-
128128-129129- ```
130130- 39 bits
131131- 2^39 = 512 GB
132132- = 0x80-0000-0000
133133- ```
134134-- But xv6 uses only 38 bits for its VAs
135135-136136- ```
137137- 38 bits
138138- 2^38 = 256 GB
139139- = 0x40-0000-0000
140140- ```
141141-- Therefore the allowed range is - 0…0x3F-FFFF-FFFF
142142-143143-144144-## Startup
145145-146146-We go from
147147-148148-```
149149- entry.S -> start.c -> main.c
150150- (Setup Stack) (Machine Mode) (Supervisor Mode)
151151-```
152152-
-274
src/content/posts/xv6-mem-management/index.md
···11----
22-title: "xv6 - Memory Management"
33-published: 2026-01-03
44-draft: false
55-description: 'How does xv6 manage memory?'
66-series: 'xv6'
77-tags: ["xv6","os"]
88----
99-1010-We know that xv6 uses a simple freelist, keeping that in mind, let's take a look at [kalloc.c](https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/kalloc.c)!
1111-1212-- ```c
1313- extern char end[];
1414- ```
1515-1616- First memory address after kernel.
1717- Defined by `kernel.ld`
1818-- ```c
1919- struct run {
2020- struct run *next;
2121- };
2222- ```
2323-2424- This is the freelist.
2525-- ```c
2626- struct {
2727- struct spinlock lock;
2828- struct run *freelist;
2929- } kmem;
3030- ```
3131-3232- Protects the freelist with a lock.
3333-- ```c
3434- void
3535- kinit()
3636- {
3737- initlock(&kmem.lock, "kmem");
3838- freerange(end, (void*)PHYSTOP);
3939- }
4040- ```
4141-4242- Initialises the lock and frees the entire memory space above the kernel.
4343-- ```c
4444- void
4545- freerange(void *pa_start, void *pa_end)
4646- {
4747- char *p;
4848- p = (char*)PGROUNDUP((uint64)pa_start);
4949- for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
5050- kfree(p);
5151- }
5252- ```
5353-5454- We go from `pa_start` to `pa_end` and free each page!
5555-5656-The next two functions do require a closer look-
5757-5858-5959-# kfree
6060-6161-```c
6262-void
6363-kfree(void *pa)
6464-{
6565- struct run *r;
6666-6767- if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
6868- panic("kfree");
6969-7070- // Fill with junk to catch dangling refs.
7171- memset(pa, 1, PGSIZE);
7272-7373- r = (struct run*)pa;
7474-7575- acquire(&kmem.lock);
7676- r->next = kmem.freelist;
7777- kmem.freelist = r;
7878- release(&kmem.lock);
7979-}
8080-```
8181-8282-Let's go line by line here.
8383-8484-1. ```c
8585- void
8686- kfree(void *pa)
8787- {
8888- struct run *r;
8989-9090- ...
9191- }
9292- ```
9393-9494- - We take in physical address (`pa`) as input, which is a pointer that points to the page we want to free.
9595- - We also create `struct run` to actually manipulate memory.
9696-2. ```c
9797- if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
9898- panic("kfree");
9999- ```
100100-101101- Here, we define the conditions in which `kfree` is invalid to run and should panic-
102102-103103- - `(uint64)pa % PGSIZE != 0` -> The pointer `pa` is not page-aligned!
104104-105105- - `(char*)pa < end` -> `pa` points to a kernel page!
106106-107107- - `(uint64)pa >= PHYSTOP` -> `pa` points to a memory address larger than the physical memory!
108108-109109-3. ```c
110110- memset(pa, 1, PGSIZE);
111111- ```
112112-113113- As is quite obvious here, we fill the entire page with junk value so a snooping program cannot see the residual data. It also helps in debugging and catching dangling refs.
114114-115115-4. ```c
116116- r = (struct run*)pa;
117117-118118- acquire(&kmem.lock);
119119- r->next = kmem.freelist;
120120- kmem.freelist = r;
121121- release(&kmem.lock);
122122- ```
123123-124124- Step-by-step execution of this block-
125125-126126- - We assign the page to `r`.
127127-128128- - We acquire the lock to memory.
129129-130130- - We prepend this page to the start of the freelist.
131131-132132- - We point the freelist pointer to `r`.
133133-134134- - We release the lock on memory we are currently holding.
135135-136136-And that concludes the `kfree` function!
137137-138138-139139-# kalloc
140140-141141-```c
142142-void *
143143-kalloc(void)
144144-{
145145- struct run *r;
146146-147147- acquire(&kmem.lock);
148148- r = kmem.freelist;
149149- if(r)
150150- kmem.freelist = r->next;
151151- release(&kmem.lock);
152152-153153- if(r)
154154- memset((char*)r, 5, PGSIZE); // fill with junk
155155- return (void*)r;
156156-}
157157-```
158158-159159-Let's again analyse each line (only unique ones)-
160160-161161-1. ```c
162162- struct run *r;
163163-164164- acquire(&kmem.lock);
165165- r = kmem.freelist;
166166- ```
167167-168168- We acquire the memory lock and point a variable `r` to it.
169169-170170-2. ```c
171171- if(r)
172172- kmem.freelist = r->next;
173173- release(&kmem.lock);
174174- ```
175175-176176- If r exists, we move freelist pointer to the 2nd node and release the lock.
177177-178178-3. ```c
179179- if(r)
180180- memset((char*)r, 5, PGSIZE); // fill with junk
181181- return (void*)r;
182182- ```
183183-184184- Again, if r exists, we fill it with junk to foil any would be snooper's plan!
185185-186186-And that concludes the `kalloc.c` file in xv6 kernel! You are finally ready to conquer your memory!!
187187-188188-Our final `kalloc.c`
189189-190190-```c
191191-// Physical memory allocator, for user processes,
192192-// kernel stacks, page-table pages,
193193-// and pipe buffers. Allocates whole 4096-byte pages.
194194-195195-#include "types.h"
196196-#include "param.h"
197197-#include "memlayout.h"
198198-#include "spinlock.h"
199199-#include "riscv.h"
200200-#include "defs.h"
201201-202202-void freerange(void *pa_start, void *pa_end);
203203-204204-extern char end[]; // first address after kernel.
205205- // defined by kernel.ld.
206206-207207-struct run {
208208- struct run *next;
209209-};
210210-211211-struct {
212212- struct spinlock lock;
213213- struct run *freelist;
214214-} kmem;
215215-216216-void
217217-kinit()
218218-{
219219- initlock(&kmem.lock, "kmem");
220220- freerange(end, (void*)PHYSTOP);
221221-}
222222-223223-void
224224-freerange(void *pa_start, void *pa_end)
225225-{
226226- char *p;
227227- p = (char*)PGROUNDUP((uint64)pa_start);
228228- for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
229229- kfree(p);
230230-}
231231-232232-// Free the page of physical memory pointed at by pa,
233233-// which normally should have been returned by a
234234-// call to kalloc(). (The exception is when
235235-// initializing the allocator; see kinit above.)
236236-void
237237-kfree(void *pa)
238238-{
239239- struct run *r;
240240-241241- if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
242242- panic("kfree");
243243-244244- // Fill with junk to catch dangling refs.
245245- memset(pa, 1, PGSIZE);
246246-247247- r = (struct run*)pa;
248248-249249- acquire(&kmem.lock);
250250- r->next = kmem.freelist;
251251- kmem.freelist = r;
252252- release(&kmem.lock);
253253-}
254254-255255-// Allocate one 4096-byte page of physical memory.
256256-// Returns a pointer that the kernel can use.
257257-// Returns 0 if the memory cannot be allocated.
258258-void *
259259-kalloc(void)
260260-{
261261- struct run *r;
262262-263263- acquire(&kmem.lock);
264264- r = kmem.freelist;
265265- if(r)
266266- kmem.freelist = r->next;
267267- release(&kmem.lock);
268268-269269- if(r)
270270- memset((char*)r, 5, PGSIZE); // fill with junk
271271- return (void*)r;
272272-}
273273-```
274274-
-223
src/content/posts/xv6-spinlocking/index.md
···11----
22-title: "xv6 - SpinLocks"
33-published: 2026-01-02
44-draft: false
55-description: 'Should I spin or should I lock?'
66-series: 'xv6'
77-tags: ["xv6","os"]
88----
99-1010-1111-1212-# Spin Locking
1313-1414-We know that xv6 uses SpinLocks, sleep and wakeup for its locking. In this post, let us discuss SpinLocks.
1515-1616-SpinLocks are defined in [spinlock.c](https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/spinlock.c).
1717-1818-1919-## Basics
2020-2121-There are primarily **two** functions related to locks, acquire and release
2222-2323-:::warning
2424-Spin Locks should not be held for a long time as spinning wastes cycles!
2525-:::
2626-2727-:::tip
2828-In such cases, consider using `sleep()` and `wakeup()`!
2929-:::
3030-3131-3232-### acquire
3333-3434-Acquiring the lock seems simple enough on the surface.
3535-3636-```c
3737-while (locked == 1);
3838-locked = 1;
3939-cpu = mycpu();
4040-```
4141-4242-But two processors can simultaniously execute this! Therefore we need an atomic operation to read and write to `locked` in one instruction. Fortunately RISC-V has one such instrcution - `AMOSWAP`, which we will use.
4343-4444-Another thing to note is that we need to disable preemption or interrupts while we are in the critical section!
4545-4646-Therefore, we have-
4747-4848-```
4949- 1 -> [ Locked ] -> y
5050- if (y != 0) try again
5151-```
5252-5353-5454-### release
5555-5656-release is quite simple, just put value 0 in the locked field!
5757-5858-5959-## Theory
6060-6161-Now, `acquire()` disables the interrupts and `release()` re-enables them. But now, situations with multiple locks becomes problematic.
6262-6363-```c
6464-acquire(&lk1);
6565-acquire(&lk2);
6666-6767-// Critical Section
6868-6969-release(&lk2); // Interrupts re-enabled prematurely!!
7070-7171-// Some more operations
7272-7373-release(&lk1);
7474-```
7575-7676-So, we store a counter `noff` and a status int `intena` (interrupts enabled) for each hart.
7777-7878-If this is the first acquire (`noff == 0`), we set `intena` to current interrupt status (0 if disables, 1 otherwise). We then increment the counter regardless.
7979-8080-During release, we decrement the counter and if it becomes 0, we restore the interrupts to their saved state in `intena`!
8181-8282-8383-## Code
8484-8585-8686-### Structure
8787-8888-The struct spinlock itself, is defined in [spinlock.h](https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/spinlock.h).
8989-9090-```c title="spinlock.h"
9191-struct spinlock {
9292- uint locked; // Is the lock held?
9393-9494- // For debugging:
9595- char *name; // Name of lock.
9696- struct cpu *cpu; // The cpu holding the lock.
9797-};
9898-```
9999-100100-It contains an int `locked`, which indicates that the lock is free/unacquired when `locked = 0` and otherwise for `locked = 1`
101101-102102-103103-### Imports
104104-105105-We first import the necessary files. Nothing too exciting here.
106106-107107-```c title="imports"
108108-#include "types.h"
109109-#include "param.h"
110110-#include "memlayout.h"
111111-#include "spinlock.h"
112112-#include "riscv.h"
113113-#include "proc.h"
114114-#include "defs.h"
115115-```
116116-117117-118118-### Initalising the lock
119119-120120-Before we can even acquire the lock, we need to actually initialise it! Its steps are easy enough to be obvious.
121121-122122-```c title="initlock"
123123-void
124124-initlock(struct spinlock *lk, char *name)
125125-{
126126- lk->name = name;
127127- lk->locked = 0;
128128- lk->cpu = 0;
129129-}
130130-```
131131-132132-133133-### Acquiring the Lock
134134-135135-Let' start writing the acquire function!
136136-137137-```c
138138-void acquire(struct spinlock *lk) {
139139- <<aq_disable_interrupt>>
140140- <<aq_atomic_swap>>
141141- <<aq_misc>>
142142-}
143143-```
144144-145145-1. As discussed earlier we first disable the interrupts. `push_off()` takes care of that. We also ensure we already aren't holding the lock.
146146-147147- ```c title="Disable Interrupts"
148148- push_off();
149149- if(holding(lk))
150150- panic("acquire");
151151- ```
152152-153153-2. ```c title="Atomic Swap and Loop"
154154- while(__sync_lock_test_and_set(&lk->locked, 1) != 0);
155155- ```
156156-157157-3. We need to ensure that compiler optimisations do not mess with the order, also store the cpu's information in the struct.
158158-159159- ```c title="Misc"
160160- __sync_synchronize();
161161- lk->cpu = mycpu();
162162- ```
163163-164164-Our final acquire function-
165165-166166-```c title="acquire"
167167-void acquire(struct spinlock *lk) {
168168- push_off();
169169- if(holding(lk))
170170- panic("acquire");
171171- while(__sync_lock_test_and_set(&lk->locked, 1) != 0);
172172- __sync_synchronize();
173173- lk->cpu = mycpu();
174174-}
175175-```
176176-177177-178178-### Releasing the lock
179179-180180-Releasing is a lot simpler.
181181-182182-```c
183183-void release(struct spinlock *lk) {
184184- <<rl_misc>>
185185- <<rl_en_int>>
186186-}
187187-```
188188-189189-1. Ensure we are holding the lock, scrub cpu information, synchronise, and release the lock
190190-191191- ```c title="Misc"
192192- if(!holding(lk))
193193- panic("release");
194194-195195- lk->cpu = 0;
196196-197197- __sync_synchronize();
198198-199199- __sync_lock_release(&lk->locked);
200200- ```
201201-202202-2. Re-enable Interrupts
203203-204204- ```c title="Interrupts"
205205- pop_off();
206206- ```
207207-208208-Release function-
209209-210210-```c title="release"
211211-void release(struct spinlock *lk) {
212212- if(!holding(lk))
213213- panic("release");
214214-215215- lk->cpu = 0;
216216-217217- __sync_synchronize();
218218-219219- __sync_lock_release(&lk->locked);
220220- pop_off();
221221-}
222222-```
223223-