#Nyaux
1 messages ยท Page 35 of 1
what
I feel like you should stop and just think for a moment what exactly do you want to do when switching between two threads
and don't tie that code to interrupts/syscalls in any way, just have a function you can use to switch between two threads
yea i save ctx, load ctx, switch pagemap
I'm back
And you switch kernel stack
Well, saving and loading ctx is part of that kinda
Or rather you save the kernel stack when you save ctx, and you load differen't thread's kernel stack when you load it
; void do_sched(Thread* old, Thread* new)
do_sched:
; save callee saved registers to the old thread's stack
push rbx
push rbp
push r12
push r13
push r14
push r15
; save rsp inside old thread
mov [rdi + Thread.saved_rsp], rsp
; load rsp from new thread
mov rsp, [rsi + Thread.saved_rsp]
; restore saved regs from the new thread's stack
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
ret
something like this is what you want to do
what so i need 2 FIELDS in interrupt context now
one for the thread stack
and one for the kernel stack
So you have something like this ```c
void switch_thread(thread *new_thread) {
struct sse_data sse;
struct gs_stuff gs;
save_sse(&sse);
save_gs(&gs);
if (new_thread->cr3 != my_cr3())
load_new_cr3(new_thread);
do_sched(new_thread);
restore_gs(&gs);
restore_sse(&sse);
}```
bro this is pain
sir why are u saving gs
u have context
and like idk why ur saving gs
Wdym
because the gsbase may be modified by the userspace using a syscall?
nvm
assuming one has such syscall
so

Potentially add more context saving functions
one for the stack pointer that you load at the start of syscall (or put in the tss rsp0 field) and one where you save the kernel rsp when switching yes
Kernel stack is part your Thread
Or a second field
You don't change user stack
No such field
yea okay so suddenly i need to save it
fun!
You save it to kernel's stack when you get interrupt
you just call your generic switching function inside there
.
No
he said no qwinci
I mean you call it from my function
no its not
yes
what if there wasnt any gps on that stack saved to begin with

That's not possible
how
You build it when you create a new thread
fun
After that, it will always have the context of the previous thread
when you initially create a thread you set the rsp inside the thread struct to point that much lower to the stack yeah
so when creating a new thread
how am i supposed to build it exactly
when creating these gps
on that kstack
you just set the saved rsp field inside the thread to be the stack top - the amount of space the registers that you expect to be on the stack
no i mean i will have to manually push values
yes?
its just a matter of doing *--thread->rsp = 0 (assuming the rsp field is a u64*) how many times you want to push
before swap gsing
No
, this is what everyone does
After swapgs
No
syscall:
swapgs
load kernel stack
push all registers
call syscall
pop all registers
swapgs
sysretq
Same, but withoug loading kernel stack
no qwinci said i need to save and load thread kstacks
if (coming from userspace)
swapgs
push all registers
call isr
pop all regisers
if (returning to userspace)
swapgs
iretq
interrupts are unrelated to task switching
^
this is task switching
Yes
my task switching is interrupt based
No
don't do that
You task switch when you decide that you want to run a different thread
you can use your task switch function inside the interrupt but it shouldn't be tied to it, you should be able to call it anywhere
You call switch_thread(new_thread)
boom
You've switched the context
Now new thread runs
It can be from syscall
It can be from interrupt
fuck u when a syscall happens im not switching the thread
Which includes timer interrupts, page faults, anything you want
You will be
no
I give up
Forget about timer interrupts
Everything will work out when you do that
Now just implement syscalls
No timer for you
why do u want me to switch threads during a syscall
yes its wasted compute time
but again
No
ok what is it then
It's wasted compute time if you don't
yea
pthread_mutex
you can eg. acquire a futex or whatever, then if the futex is acquired you want to switch to some other thread
yeah

its stupid to tie task switching to interrupts
Your timer interrupt should just call a c function
Where you find a next task
mhm
And call this
with the new task
If you want to switch from a syscall, you also call this function
and then what
i have to switch kstacks
save and load kstack
when switching threads
doesnt matter if its from syscall or interrupt
This is all you have to do
Yes
yea i dont see any saving and loading of kstacks
Because it's the same function
If you don't switch threads, you don't load new kstacks
mhm
so, in your timer interrupt function
You
- save all registers to stack
- call C
- restore all registers from stack
- iretq
If your timer isr decides to reschedule, it calls this (from C)
ok so when swithcing threads i must
mov [oldthread.kstack], rsp
; switch threads
mov rsp, [newthread.stack]
You're returning to a different task
pesudo code btw
yes like the do_sched function that I sent does
(that's used by the code that mishakov sent)
And you always call that from switch_thread
Create a new nasm file, and paste this code
you already have asm files tho and they are arch specific
ITS FINE okay ill js make the inline asm volatile so compiler doesnt mess with shit and try to add nostack or wtv
yea
but they call non arch specific code
not get called by non arch specific code
why does that matter
at least make it global inline asm then and not inside a c function lol
wtf
Also
union thread {
struct thread t;
uint64_t kernel_stack[2048];
};
Probably
no thanks

ok now on thread create i must put the ctx in the kstack
TIME TO DO THIS MANUALLY

wait i have a better idea
better idea done
๐
-= whoops
and i should -= before
then load the value
done
opinion on this masterpiece of code
๐
now according to my calculations this should work
SO CLOSE
ugh
so its that function

why
You're doing it wrong
Remove these functions
Replace them with qwinci's code
No
wdym no?
Have you implemented this?
done via inline asm yes
Show it
I don't see
; void do_sched(Thread* old, Thread* new)
do_sched:
; save callee saved registers to the old thread's stack
push rbx
push rbp
push r12
push r13
push r14
push r15
; save rsp inside old thread
mov [rdi + Thread.saved_rsp], rsp
; load rsp from new thread
mov rsp, [rsi + Thread.saved_rsp]
; restore saved regs from the new thread's stack
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
ret
bro timer interrupt saved the registers
sorry but
I hate your colorscheme so much
It saves userspace registers
You need to be saving kernel registers
as well
probably why you get so many bugs
good colorscheme == less bugs
this is a known fact
fine
wrong
I've been using white color scheme and didn't have bugs
no it's true
there are good light colorschemes tho
like solarized light
or ayu-light
Bugs burn when they touch lightbulbs 
gruvbox light isnt that bad either
ok now somethings starting to break my brain
if we are loading kernel registers and saving them
what about
the registers we saved at the start of the timer interrupt
the userspace ones
You save them to kernel stack

Which is one per userspace thread
You then switch kernel stacks/contexts
The cpu now has different thread's stack in its %rsp
You restore registers from the stack
The kernel stack for the different thread has its registers saved
So you restore registers of a different thread
what stack do we load at the start of the isr
if its the one from ist
we are just loading some rand kstack
when we enter an interrupt
then we save those values???
??????????????????????????????????????
You also change stacks in TSS
So the right thread's kernel stack is always loaded in isr
bro
now i need a tss
and an isr
fuck u man for making me do all this work 
specifically
Or wherever
I don't remember
Where does kernel get its stack on interrupt
From there
i currently dont even have an isr
Sorry I didn't invent x86
yea why does x86 make everything so annoying
;no

ugh
so now i need
a tss
an ist
for a seperate kstack
then after saving userspace regs
i need to save kstack regs
Ist?
kernel*
interrupt stack table
so now i need to create like 2 kstacks
one for the interrupt on entry
and one for the threads kstack
No
wdym no???
One stack
Which you load into rsp0 (?)
into rsp0
Forget about ist
bro
into rsp0
fucking hell
i need to somehow
already be in a thread
change out rsp0
fucking hell bro
im reading the fucking manual chill
whats cringe is that i have to do all this housekeeping for what
so annoying
save userspace regs, when switching tasks save kernel regs. switch out rsp 0. switch out rsp, load kernel regs, when in intererupt or syscall or whatever reload userspace regs iretq
or sysretq
or wtv
then do it all out again
yea im taking a nap no1
no2 im doing this when i wake up
not in the mood rn
x86 is cringe for this
I just have rsp0 set to a per-cpu specific stack
and not to a per-thread stack
then I do have a per-thread kernel stack
but that's for syscalls only
swapgs
mov r10, rsp
; Switch to a temporary stack
mov rsp, [gs:0xc8]
add rsp, 0x20000
push rdx
mov rdx, [Arch_KernelCR3]
mov cr3, rdx
pop rdx
; Switch to the thread's 'proper' stack
mov rsp, [Arch_cpu_local_currentKernelStack_offset] ; hacky, but works
mov rsp, [gs:rsp]
add rsp, 0x10000```
the reason I first switch to a per-cpu temporary stack is because I didn't want to map the per-thread kernel stack into that process' CR3 (I do kpti)
You use different kernel mappings per process?
not quite
I do kernel page table isolation
to only map the bare minimum of the kernel into a process' context
the bare minimum is anything needed by isr handlers and the syscall handlers
which are stuff like, per-cpu temporary stacks, idt, gdt, etc.
as well as the function CoreS_SwitchToThreadContext
which switches to a thread context
tho, is it part of the codebase typing everything without having proper spacing between lines?
i blame my editor
someone give me vscode settings that doesnt cause this
or a better code editor idfk
you could just format them in a sensible way yourself
the style is also inconsistent within the codebase, somewhere 2 space tabs are used (ew) and others proper tabs
sure
๐ญ
nah if u actually do fix it ill try to actually keep consistent formatting
for once
cause id feel bad
yeah that would be an option too, though sometimes it creates weird looking code that's far from perfect
which is why I don't really use it, I just write code with sensible formatting to begin with
its not just the formatting
the erratic naming makes things difficult to follow
and lack of defining constants
good point
serenity
going forward ill try to use naming
proper
and proper constants
im not gonna go into the codebase and change the existing naming however thats too much work and i have a lot to do today
with the nyaux kernel itself
likkkeee actually having a tss
and
adding all that shit mr @flat nymph wants
because its what everyone does lol
anyways we start programming
so looking at the tss
it seems to be 100 bytes long?
weirdly
weird number but ok
well no
its 100 * 4
400 bytes?
wiki makes it confusing
its 104 bytes
do you have some kind of extension/setting related to code formatting on save?
no
;cpp << (27 * 4)
108
It's not even on of these right? (sorry if i'm interrupting you from the other stuff you're doing)
its on now
time to make a gdt entry describing my tss
mh
no its virtual address
oh okay
thanks for osdev wiki for giving me the access byte i needed
0x89
flags should be empty
limit is the size of the tss
okay lets get cooking
ayu dark spotted
based
okay so
i might need 2 entries to describe the tss
in the gdt
i just realized its a 128bit entry
so i need 2 entries
lower half first higher half second
actually
"About
Combination theme for VS Code and VSCodium that inspired from Ayu Theme, Monokai , Andromeda, Material Color, and Gruvbox Darktooth Color."
okay i constructed this
i know i will need to do some bitshifting if i want to or this
but thats good
nevermind
because for SOME reason
x86 thought it would be a good idea
to have base seperated into 5 PIECES
cringe
wait no thats limit
im idiot
just tame it with //
eh I don't want to do that every time I construct an object using a designated initializer
is it cpp const auto my_object = Object{ xxx, yyy, zzz };
vscpp const auto my_object = Object{ xxx, yyy, zzz, };
?
if so, trailing comma
now for the second entry
that should be the 2
time to add the entries into the gdt and try it out
wheres my __builtin_trap()

we will check if this works
it does
okay
mmm
thats bad
it says my tss is still busy
tf

WHY IS MY TSS STILL BUSY
๐ญ
zig moment
thjat's c++ lol
uint64_t tssaddress = (uint64_t)&tss;
uint16_t base_low = tssaddress & 0xFFFF;
uint8_t base_mid = (tssaddress >> 16) & 0xFF;
uint8_t base_midhi = (tssaddress >> 24) & 0xFF;
uint32_t base_hi = (tssaddress >> 32) & 0xFFFFFFFF;
uint8_t access_byte = 0x89; // stolen from osdev wiki cause im lazy to construct my own
// basically what it means is it describes the tss as avabile and stuff
uint64_t constructedlow = ((uint64_t)base_low << 16) | ((uint64_t)base_mid << 32) | ((uint64_t)base_midhi << 56) access_byte | sizeof(tss) - 1;
uint64_t constructedhi = (uint64_t)base_hi;
gdt[9] = constructedlow;
gdt[10] = constructedhi;
okay so this is my constructed shit right
it still thinks its busy
which makes no sense
and the bases are all bitshifted correctly
maybe the size cannot fit in 16 bits
but i doubt it
hold on\
yea it can fit
time to print the entries in binary
and go over it

@molten grotto whats the nanoprintf's binary %
if u know
i swear there is one
that (also with functions) and ```cpp
inline constexpr Ps2Cmd RESET {
.cmd = 0xFF,
.params = 0,
.ret = 2
};
??\
just wait a moment lol
okay lol
its the same as in ansi c, %b
though you need to define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS
okay hold on
same, trailing comma
lub is not a valid format
oh
%lb
thanks
so
this is the entry for constructed low
hold on
js fixed my leds
SO BACK TO WHAT WE WERE SAYING
0000000010001001
thats the limit
137?
thats the size of the tss
how???
its 26 entries
you forgot e at the end
lol
@molten grotto is that bad
why not just make a struct
104
yea i think i need to be the array packed
I CANT MAKE IT PACKED
BRO
so the gdt is right
struct tss
{
u32 reserved
u64 rsp[3]
u64 reserved
u64 ist[7]
u64 reserved
u16 reserved
u16 iopb
} attribute packed
why ugh
array is the worst way
just a tad better than manually entering each byte
i dont know why i keep saying ugh
my bad
im sorry ilobilo
okay im doing it @edgy pilot
why are you saying smh ๐ญ
low high u32 is just one u64
just copy this
wait yea i know what to do!!!
okay @edgy pilot
huh
thats the tss now
not u8
the comment is incorrect too
good job
now you can run Minecraft
๐ญ ๐ญ
doom first
yes ofc
will this be zerod out
i suppose it would be
YESS
ITS 104
tss is still busy ๐
{ 0 }
yea so whats going on
i cant speak im sick
I can't sick I'm speak
bru
yea its correct
yea they are not answering
@molten grotto do u know whats going on
I can try to help after I finish ow match
okayokay
did you load the tss with ltr @surreal path
OHHHHH
what value should i give the tss @molten grotto
its address?
yea
the offset of the tss entry in the gdt
you have 17 entries in your gdt?
then how can the offset of the tss entry be 0x80
that's even more lol
its saying
iirc its ltr [offset]
thanks
fix the offset first tho
like what is the byte offset from the start of the gdt to the tss entry
its in decimal not hex
I'm doing ltr %ax
oh yeah I misremembered ๐ that's how you are supposed to do it, you move the offset to a register and then do that
okay
wheres tss
is that a good thing that its no longer busy @molten grotto
and it isnt even there
in the qemu log
what is the asm that you use to load it rn (just to make sure)?
ltr takes in a 16-bit r/m
r/m?
register or memory
okay
meaning it either takes in a 16-bit register or a 16-bit memory location to load the offset from
it looks like you aren't setting the limit?
the entry is still wrong, Ill leave it as an exercise for you to figure out how
okay
hmmm
yea thats completely wrong
oh right
i didnt shift the access byte
my bad
yea this is correct
lets go
we have a tss now
Btw, you need a TSS per CPU
no
no because the address will be totally different per cpu
you can just set the address, do ltr and then switch the address
because i have to put it in a per cpu data struct

as long as you guard the gdt entry setting + ltr with a spinlock so the cpus don't try to modify the entry at the same time
????
Probably
Why
and then
I mean you can
how does that help with anything
Or you can just put it there directly
^
It's 3 extra lines of code
i know
ok there
okay so
its 0xding at line 13
i set the last two values where there would be a tss segment descriptor to 0
that shouldn't be a problem right?
Just set it in C
no thanks
do you pass the second arg as 1
no
hold on
if its true
i pass in 1
or well
a bool
thats just really 1
tbf
then its going to try loading the null tss entry on the bsp
why??
no but i skip the load
Why do you even pass it?
doesnt rlly matter
js
dunno whats going on
the tss entries are null
i skipped the load
why is cpu mad
Yes?
and it will skip the load
You're giving it null entries
okay then what am i supposed to do, how do i tell mr cpu theres no tss atm
Why are you skipping it
You don't
Just initialize it
you should have the tss for the bsp at that point
You don't need gdt for kmalloc
arch init is loaded
init gdt is given true
meaning it will skip the load
so it skips the load
i have a hacky solution
or you can statically allocate the cpu struct for the bsp cpu
no
But that wastes 104 bytes of RAM 
Unless you put it into init section which gets discarded
initally
Wtf
I mean you are going to use the same amount of ram regardless whether you statically allocate it or use kmalloc
^
no
Why not
This wastes less memory than kmalloc'ing it
im not kmallocing anything
it doesn't waste any memory to statically allocate the bsp struct
You'll have to 
why
now its dying
when trying to use my new gdt
at ltr
when loading the tss offset
huh wtf???
ugh fine ill statically allocate it
huh???

WHAT IS GOIGN ON

NOW MEMORY BUGS??
WHAT
oh
IM DOING THIS
fucking end me
now we have UB
and bugs
and bug
and i have NO idea whats going on

@molten grotto i thought we solved the memory bugs
happening on line 163????
end me
end me
Btw, bsp's lapic id is not always 0
oh then am i supposed to idendtify if i am bsp
Get if from limine
yeah the limine smp request contains the bsp id
And store it as a global variable or something
fine
or you can just get it yourself on the bsp before letting the other cores to your kernel code
I STILL HAVE NO IDEA WHATS GOING ON
I DID THAT
STILL UB
STILL BUGS
sometimes its a 0xd
sometimes its a 0xe
it doesnt care
its happening
when loading
the tss
BRO
yep my tss is creating ub
i want to die
well
its all pushed to github

and the rip is different each time so its ub
?????????????????????
โ
โ
I DONT KNOW WHATS GOING ON
literarly
*literally
that's your job bru
i legit dont know
i cant find anything useful
im just loading the tss
how is this causing ub
๐ญ
not everything is UB
well this is
ub means undefined behaviour
yea
skill issue isn't ub
its ub
because
theres different things happening
on each reboot
so its def UB
that's not ub
yea its skill issue whatever u wanna say
no, you are severely misunderstanding what UB means
explain
Undefined Behaviour, doing things in a language that have not been defined by the standard
not bugs in code
then its not ub
that's just bugs
then its bugs
whatever
bugs i cannot figure out because on every reboot something is different
which makes no sense
and drives me insane
ur saying this like i dont have problem solving skills
engage your brain and think, mark, THINK!
nah you're just not using it
insulting is very different from criticising
good night
goodnight
ok i cant sleep
ill try to figure this out
okay
i caught something
ill add an assert
okay
there are 2 behavioras
that happens
this is the first one
and the second is this
no idea
printing the value now produces consistent behavior
nvm
its not
so none of this happened before adding the TSS
but the tss shows
this is confusing
what's going on
no absolute idea
and im glad ur here
because i am struggling
ever since ive tried to add this TSS
its been causing me a TON of UB
is the code on gh?
yes!
alrighty gimme a sec
kk!
@surreal path
yea?
the IOBP thing has to be set afaik
set to what?
ur saying the base is at the end of the tss
how so?
and the tss size tells it that the size of the map is zero
explain further
yeah I am pretty sure u gotta do that
okay i did that here
how tho?
by setting the base to sizeof(tss)
i did not tho?base is the tss address
the IOBP is the base offset
I'm not setting that
hm
I don't have it
???
afaik iopb is optional
yea
This is what I'm doing
struct GDT {
GDT_entry Null {}; // always null
GDT_entry _64bit_kernel_code {0, 0, 0, 0x9a, 0xa2, 0};
GDT_entry _64bit_kernel_data {0, 0, 0, 0x92, 0xa0, 0};
GDT_entry _32bit_user_code {0xffff, 0, 0, 0xfa, 0xcf, 0};
GDT_entry user_data_1 {0xffff, 0, 0, 0xf2, 0xcf, 0};
GDT_entry _64bit_user_code {0, 0, 0, 0xfa, 0xa0, 0};
GDT_entry user_data_2 {0xffff, 0, 0, 0xf2, 0xcf, 0};
GDT_entry ring2_code {0, 0, 0, 0xda, 0xa0, 0};
GDT_entry ring2_data {0, 0, 0, 0xd2, 0xa0, 0};
System_Segment_Descriptor tss_descriptor;
constexpr u16 get_size() { return sizeof(GDT) - 1; }
} PACKED ALIGNED(8);
struct System_Segment_Descriptor {
u16 limit0;
u16 base0;
u8 base1;
u8 access;
u8 limit1 : 4;
u8 flags : 4;
u8 base2;
u32 base3;
u32 reserved;
constexpr System_Segment_Descriptor(): System_Segment_Descriptor(0, 0, 0, 0) {}
constexpr System_Segment_Descriptor(u64 base, u32 limit, u8 access, u8 flags)
: limit0(limit & 0xffff), base0(base & 0xffff), base1((base >> 16) & 0xff), access(access),
limit1((limit >> 16) & 0xff), flags(flags), base2((base >> 24) & 0xff),
base3((base >> 32) & 0xffffffff), reserved(0)
{
}
TSS *tss();
} PACKED;
c->cpu_gdt.tss_descriptor = System_Segment_Descriptor((u64)tss, sizeof(TSS), 0x89, 0x02);
I'm not liking it
lol
i lit do what u do for creating the systemsegment descriptor
so no idea
Same access and flags?
yep
Are you sure the problem is here?
How does it crash
i said above here and #osdev-misc-0
what does 0x02 in flags do there
I have no idea
lol
this?
DB: Size flag. If clear (0), the descriptor defines a 16-bit protected mode segment. If set (1) it defines a 32-bit protected mode segment. A GDT can have both 16-bit and 32-bit selectors at once.
I don't think that would affect anything
it works right?
Yeah
then it is not :p
I am reading through the manuals and cant figure out how this works
afaik it cannot be "disabled"?
atleast the manuals dont mention this
Where does this happen?
io access from userspace is disabled by default
randomly
you don't touch it if you don't want it enabled
Which line does it point to
sure but what governs this
doesnt the iobp govern this
hmmmm
like if u set it to zero
I guess it being set to 0 disables it